Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
- madprogrammer
- danielmoos
- sigeryang
- bet4it


#### Legacy Core Developers
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
Qiling is an advanced binary emulation framework, with the following features:

- Emulate multi-platforms: Windows, MacOS, Linux, BSD, UEFI, DOS, MBR, Ethereum Virtual Machine
- Emulate multi-architectures: X86, X86_64, Arm, Arm64, MIPS, 8086
- Emulate multi-architectures: 8086, X86, X86_64, ARM, ARM64, MIPS, RISCV, PowerPC
- Support multiple file formats: PE, MachO, ELF, COM, MBR
- Support Windows Driver (.sys), Linux Kernel Module (.ko) & MacOS Kernel (.kext) via [Demigod](https://groundx.io/demigod/)
- Emulates & sandbox code in an isolated environment
Expand Down
51 changes: 51 additions & 0 deletions qiling/arch/ppc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from functools import cached_property

from unicorn import Uc, UC_ARCH_PPC, UC_MODE_PPC32, UC_MODE_BIG_ENDIAN
from capstone import Cs, CS_ARCH_PPC, CS_MODE_32, CS_MODE_BIG_ENDIAN
from keystone import Ks, KS_ARCH_PPC, KS_MODE_PPC32, KS_MODE_BIG_ENDIAN

from qiling import Qiling
from qiling.arch.arch import QlArch
from qiling.arch import ppc_const
from qiling.arch.register import QlRegisterManager
from qiling.const import QL_ARCH, QL_ENDIAN

class QlArchPPC(QlArch):
type = QL_ARCH.PPC
bits = 32

@cached_property
def uc(self) -> Uc:
return Uc(UC_ARCH_PPC, UC_MODE_PPC32 + UC_MODE_BIG_ENDIAN)

@cached_property
def regs(self) -> QlRegisterManager:
regs_map = dict(
**ppc_const.reg_map,
**ppc_const.reg_float_map
)

pc_reg = 'pc'
sp_reg = 'r1'

return QlRegisterManager(self.uc, regs_map, pc_reg, sp_reg)

@cached_property
def disassembler(self) -> Cs:
return Cs(CS_ARCH_PPC, CS_MODE_32 + CS_MODE_BIG_ENDIAN)

@cached_property
def assembler(self) -> Ks:
return Ks(KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN)

@property
def endian(self) -> QL_ENDIAN:
return QL_ENDIAN.EB

def enable_float(self):
self.regs.msr = self.regs.msr | ppc_const.MSR.FP
128 changes: 128 additions & 0 deletions qiling/arch/ppc_const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#

from unicorn.ppc_const import *
from enum import IntEnum

reg_map = {
"r0": UC_PPC_REG_0,
"r1": UC_PPC_REG_1,
"r2": UC_PPC_REG_2,
"r3": UC_PPC_REG_3,
"r4": UC_PPC_REG_4,
"r5": UC_PPC_REG_5,
"r6": UC_PPC_REG_6,
"r7": UC_PPC_REG_7,
"r8": UC_PPC_REG_8,
"r9": UC_PPC_REG_9,
"r10": UC_PPC_REG_10,
"r11": UC_PPC_REG_11,
"r12": UC_PPC_REG_12,
"r13": UC_PPC_REG_13,
"r14": UC_PPC_REG_14,
"r15": UC_PPC_REG_15,
"r16": UC_PPC_REG_16,
"r17": UC_PPC_REG_17,
"r18": UC_PPC_REG_18,
"r19": UC_PPC_REG_19,
"r20": UC_PPC_REG_20,
"r21": UC_PPC_REG_21,
"r22": UC_PPC_REG_22,
"r23": UC_PPC_REG_23,
"r24": UC_PPC_REG_24,
"r25": UC_PPC_REG_25,
"r26": UC_PPC_REG_26,
"r27": UC_PPC_REG_27,
"r28": UC_PPC_REG_28,
"r29": UC_PPC_REG_29,
"r30": UC_PPC_REG_30,
"r31": UC_PPC_REG_31,
"pc": UC_PPC_REG_PC,
"msr": UC_PPC_REG_MSR,
"cr": UC_PPC_REG_CR0,
"lr": UC_PPC_REG_LR,
"ctr": UC_PPC_REG_CTR,
"xer": UC_PPC_REG_XER,
}

reg_float_map = {
"f0": UC_PPC_REG_FPR0,
"f1": UC_PPC_REG_FPR1,
"f2": UC_PPC_REG_FPR2,
"f3": UC_PPC_REG_FPR3,
"f4": UC_PPC_REG_FPR4,
"f5": UC_PPC_REG_FPR5,
"f6": UC_PPC_REG_FPR6,
"f7": UC_PPC_REG_FPR7,
"f8": UC_PPC_REG_FPR8,
"f9": UC_PPC_REG_FPR9,
"f10": UC_PPC_REG_FPR10,
"f11": UC_PPC_REG_FPR11,
"f12": UC_PPC_REG_FPR12,
"f13": UC_PPC_REG_FPR13,
"f14": UC_PPC_REG_FPR14,
"f15": UC_PPC_REG_FPR15,
"f16": UC_PPC_REG_FPR16,
"f17": UC_PPC_REG_FPR17,
"f18": UC_PPC_REG_FPR18,
"f19": UC_PPC_REG_FPR19,
"f20": UC_PPC_REG_FPR20,
"f21": UC_PPC_REG_FPR21,
"f22": UC_PPC_REG_FPR22,
"f23": UC_PPC_REG_FPR23,
"f24": UC_PPC_REG_FPR24,
"f25": UC_PPC_REG_FPR25,
"f26": UC_PPC_REG_FPR26,
"f27": UC_PPC_REG_FPR27,
"f28": UC_PPC_REG_FPR28,
"f29": UC_PPC_REG_FPR29,
"f30": UC_PPC_REG_FPR30,
"f31": UC_PPC_REG_FPR31,
}

class MSR(IntEnum):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that Flag ot IntFlag would be a better fit here (see here).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could search IntEnum in the code. There are many usages of IntEnum, but none of Flag or IntFlag. So if we really want to change it, that could be another PR.

SF = 1 << 63
TAG = 1 << 62
ISF = 1 << 61
HV = 1 << 60
TS0 = 1 << 34
TS1 = 1 << 33
TM = 1 << 32
CM = 1 << 31
ICM = 1 << 30
GS = 1 << 28
UCLE = 1 << 26
VR = 1 << 25
SPE = 1 << 25
AP = 1 << 23
VSX = 1 << 23
SA = 1 << 22
KEY = 1 << 19
POW = 1 << 18
TGPR = 1 << 17
CE = 1 << 17
ILE = 1 << 16
EE = 1 << 15
PR = 1 << 14
FP = 1 << 13
ME = 1 << 12
FE0 = 1 << 11
SE = 1 << 10
DWE = 1 << 10
UBLE = 1 << 10
BE = 1 << 9
DE = 1 << 9
FE1 = 1 << 8
AL = 1 << 7
EP = 1 << 6
IR = 1 << 5
DR = 1 << 4
IS = 1 << 5
DS = 1 << 4
PE = 1 << 3
PX = 1 << 2
PMM = 1 << 2
RI = 1 << 1
LE = 1 << 0
7 changes: 4 additions & 3 deletions qiling/arch/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
from os.path import basename
from functools import lru_cache

from keystone import (Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_X86,
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
from keystone import (Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_X86, KS_ARCH_PPC,
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_PPC32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
KS_MODE_LITTLE_ENDIAN, KS_MODE_BIG_ENDIAN)

from qiling import Qiling
Expand Down Expand Up @@ -104,7 +104,8 @@ def assembler(arch: QL_ARCH, endianess: QL_ENDIAN, is_thumb: bool) -> Ks:
QL_ARCH.MIPS : (KS_ARCH_MIPS, KS_MODE_MIPS32 + endian),
QL_ARCH.A8086 : (KS_ARCH_X86, KS_MODE_16),
QL_ARCH.X86 : (KS_ARCH_X86, KS_MODE_32),
QL_ARCH.X8664 : (KS_ARCH_X86, KS_MODE_64)
QL_ARCH.X8664 : (KS_ARCH_X86, KS_MODE_64),
QL_ARCH.PPC : (KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN)
}

if arch in asm_map:
Expand Down
23 changes: 23 additions & 0 deletions qiling/cc/ppc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework

from qiling.cc import QlCommonBaseCC

from unicorn.ppc_const import (
UC_PPC_REG_3, UC_PPC_REG_4, UC_PPC_REG_5,
UC_PPC_REG_6, UC_PPC_REG_7, UC_PPC_REG_8,
)


class ppc(QlCommonBaseCC):
"""Default calling convention for PPC
First 6 arguments are passed in regs, the rest are passed on the stack.
"""

_retreg = UC_PPC_REG_3
_argregs = (UC_PPC_REG_3, UC_PPC_REG_4, UC_PPC_REG_5, UC_PPC_REG_6, UC_PPC_REG_7, UC_PPC_REG_8) + (None, ) * 10

@staticmethod
def getNumSlots(argbits: int):
return 1
1 change: 1 addition & 0 deletions qiling/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class QL_ARCH(IntEnum):
CORTEX_M = 109
RISCV = 110
RISCV64 = 111
PPC = 112

class QL_OS(IntEnum):
LINUX = 201
Expand Down
15 changes: 9 additions & 6 deletions qiling/os/blob/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

from qiling import Qiling
from qiling.cc import QlCC, intel, arm, mips
from qiling.cc import QlCC, intel, arm, mips, riscv, ppc
from qiling.const import QL_ARCH, QL_OS
from qiling.os.fcall import QlFunctionCall
from qiling.os.os import QlOs
Expand All @@ -26,11 +26,14 @@ def __init__(self, ql: Qiling):
self.ql = ql

cc: QlCC = {
QL_ARCH.X86 : intel.cdecl,
QL_ARCH.X8664 : intel.amd64,
QL_ARCH.ARM : arm.aarch32,
QL_ARCH.ARM64 : arm.aarch64,
QL_ARCH.MIPS : mips.mipso32
QL_ARCH.X86 : intel.cdecl,
QL_ARCH.X8664 : intel.amd64,
QL_ARCH.ARM : arm.aarch32,
QL_ARCH.ARM64 : arm.aarch64,
QL_ARCH.MIPS : mips.mipso32,
QL_ARCH.RISCV : riscv.riscv,
QL_ARCH.RISCV64 : riscv.riscv,
QL_ARCH.PPC : ppc.ppc,
}[ql.arch.type](ql.arch)

self.fcall = QlFunctionCall(ql, cc)
Expand Down
45 changes: 21 additions & 24 deletions qiling/os/linux/function_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def get_ret_pc(self):
elif self.ql.arch.type == QL_ARCH.ARM64:
return self.ql.arch.regs.x30

# PPC
elif self.ql.arch.type== QL_ARCH.PPC:
return self.ql.arch.regs.lr

# X86
elif self.ql.arch.type == QL_ARCH.X86:
return self.ql.unpack(self.ql.mem.read(self.ql.arch.regs.esp, self.ql.arch.pointersize))
Expand All @@ -98,6 +102,10 @@ def context_fixup(self):
elif self.ql.arch.type == QL_ARCH.MIPS:
pass

# PPC
elif self.ql.arch.type== QL_ARCH.PPC:
pass

# ARM64
elif self.ql.arch.type == QL_ARCH.ARM64:
pass
Expand All @@ -121,6 +129,10 @@ def set_ret(self, addr):
elif self.ql.arch.type == QL_ARCH.MIPS:
self.ql.arch.regs.ra = addr

# PPC
elif self.ql.arch.type== QL_ARCH.PPC:
self.ql.arch.regs.lr = addr

# ARM64
elif self.ql.arch.type == QL_ARCH.ARM64:
self.ql.arch.stack_write(0, addr)
Expand Down Expand Up @@ -173,29 +185,6 @@ def call_enter(self):
else:
self.context_fixup()

def ret(self):
# ARM
if self.ql.arch.type == QL_ARCH.ARM:
self.ql.arch.regs.arch_pc = self.ret_pc

# MIPS32
elif self.ql.arch.type == QL_ARCH.MIPS:
self.ql.arch.regs.arch_pc = self.ret_pc

# ARM64
elif self.ql.arch.type == QL_ARCH.ARM64:
self.ql.arch.regs.arch_pc = self.ret_pc

# X86
elif self.ql.arch.type == QL_ARCH.X86:
self.ql.arch.regs.arch_pc = self.ret_pc

# X8664
elif self.ql.arch.type == QL_ARCH.X8664:
self.ql.arch.regs.arch_pc = self.ret_pc
else:
raise

def call_exit(self):
# if self.ql.arch.type == QL_ARCH.ARM or self.ql.arch.type == QL_ARCH.ARM64:
# self.ql.arch.regs.arch_pc = self.ql.arch.regs.arch_pc + 4
Expand All @@ -211,7 +200,7 @@ def call_exit(self):
else:
onexit_cb(self.ql, onexit_userdata)

self.ret()
self.ql.arch.regs.arch_pc = self.ret_pc


class HookFuncRel(HookFunc):
Expand Down Expand Up @@ -614,6 +603,14 @@ def __init__(self, ql, phoff, phnum, phentsize, load_base, hook_mem):
ins = b'\x00\x01'
self.add_function_hook = self.add_function_hook_relocation

# PowerPC
elif self.ql.arch.type== QL_ARCH.PPC:
self.GLOB_DAT = 21
self.JMP_SLOT = 22
# nop
ins = b'\x60\x00\x00\x00'
self.add_function_hook = self.add_function_hook_relocation

self._parse()
if self.rel != None:
self.show_relocation(self.rel)
Expand Down
Loading