Skip to content

Commit 6fe3fa4

Browse files
authored
Merge pull request #1140 from bet4it/powerpc
Introduce PowerPC architecture to qiling
2 parents 59d31c2 + eec7db5 commit 6fe3fa4

File tree

19 files changed

+830
-58
lines changed

19 files changed

+830
-58
lines changed

CREDITS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
- madprogrammer
5454
- danielmoos
5555
- sigeryang
56+
- bet4it
5657

5758

5859
#### Legacy Core Developers

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
Qiling is an advanced binary emulation framework, with the following features:
1414

1515
- Emulate multi-platforms: Windows, MacOS, Linux, BSD, UEFI, DOS, MBR, Ethereum Virtual Machine
16-
- Emulate multi-architectures: X86, X86_64, Arm, Arm64, MIPS, 8086
16+
- Emulate multi-architectures: 8086, X86, X86_64, ARM, ARM64, MIPS, RISCV, PowerPC
1717
- Support multiple file formats: PE, MachO, ELF, COM, MBR
1818
- Support Windows Driver (.sys), Linux Kernel Module (.ko) & MacOS Kernel (.kext) via [Demigod](https://groundx.io/demigod/)
1919
- Emulates & sandbox code in an isolated environment

qiling/arch/ppc.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#
5+
6+
from functools import cached_property
7+
8+
from unicorn import Uc, UC_ARCH_PPC, UC_MODE_PPC32, UC_MODE_BIG_ENDIAN
9+
from capstone import Cs, CS_ARCH_PPC, CS_MODE_32, CS_MODE_BIG_ENDIAN
10+
from keystone import Ks, KS_ARCH_PPC, KS_MODE_PPC32, KS_MODE_BIG_ENDIAN
11+
12+
from qiling import Qiling
13+
from qiling.arch.arch import QlArch
14+
from qiling.arch import ppc_const
15+
from qiling.arch.register import QlRegisterManager
16+
from qiling.const import QL_ARCH, QL_ENDIAN
17+
18+
class QlArchPPC(QlArch):
19+
type = QL_ARCH.PPC
20+
bits = 32
21+
22+
@cached_property
23+
def uc(self) -> Uc:
24+
return Uc(UC_ARCH_PPC, UC_MODE_PPC32 + UC_MODE_BIG_ENDIAN)
25+
26+
@cached_property
27+
def regs(self) -> QlRegisterManager:
28+
regs_map = dict(
29+
**ppc_const.reg_map,
30+
**ppc_const.reg_float_map
31+
)
32+
33+
pc_reg = 'pc'
34+
sp_reg = 'r1'
35+
36+
return QlRegisterManager(self.uc, regs_map, pc_reg, sp_reg)
37+
38+
@cached_property
39+
def disassembler(self) -> Cs:
40+
return Cs(CS_ARCH_PPC, CS_MODE_32 + CS_MODE_BIG_ENDIAN)
41+
42+
@cached_property
43+
def assembler(self) -> Ks:
44+
return Ks(KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN)
45+
46+
@property
47+
def endian(self) -> QL_ENDIAN:
48+
return QL_ENDIAN.EB
49+
50+
def enable_float(self):
51+
self.regs.msr = self.regs.msr | ppc_const.MSR.FP

qiling/arch/ppc_const.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
#
5+
6+
from unicorn.ppc_const import *
7+
from enum import IntEnum
8+
9+
reg_map = {
10+
"r0": UC_PPC_REG_0,
11+
"r1": UC_PPC_REG_1,
12+
"r2": UC_PPC_REG_2,
13+
"r3": UC_PPC_REG_3,
14+
"r4": UC_PPC_REG_4,
15+
"r5": UC_PPC_REG_5,
16+
"r6": UC_PPC_REG_6,
17+
"r7": UC_PPC_REG_7,
18+
"r8": UC_PPC_REG_8,
19+
"r9": UC_PPC_REG_9,
20+
"r10": UC_PPC_REG_10,
21+
"r11": UC_PPC_REG_11,
22+
"r12": UC_PPC_REG_12,
23+
"r13": UC_PPC_REG_13,
24+
"r14": UC_PPC_REG_14,
25+
"r15": UC_PPC_REG_15,
26+
"r16": UC_PPC_REG_16,
27+
"r17": UC_PPC_REG_17,
28+
"r18": UC_PPC_REG_18,
29+
"r19": UC_PPC_REG_19,
30+
"r20": UC_PPC_REG_20,
31+
"r21": UC_PPC_REG_21,
32+
"r22": UC_PPC_REG_22,
33+
"r23": UC_PPC_REG_23,
34+
"r24": UC_PPC_REG_24,
35+
"r25": UC_PPC_REG_25,
36+
"r26": UC_PPC_REG_26,
37+
"r27": UC_PPC_REG_27,
38+
"r28": UC_PPC_REG_28,
39+
"r29": UC_PPC_REG_29,
40+
"r30": UC_PPC_REG_30,
41+
"r31": UC_PPC_REG_31,
42+
"pc": UC_PPC_REG_PC,
43+
"msr": UC_PPC_REG_MSR,
44+
"cr": UC_PPC_REG_CR0,
45+
"lr": UC_PPC_REG_LR,
46+
"ctr": UC_PPC_REG_CTR,
47+
"xer": UC_PPC_REG_XER,
48+
}
49+
50+
reg_float_map = {
51+
"f0": UC_PPC_REG_FPR0,
52+
"f1": UC_PPC_REG_FPR1,
53+
"f2": UC_PPC_REG_FPR2,
54+
"f3": UC_PPC_REG_FPR3,
55+
"f4": UC_PPC_REG_FPR4,
56+
"f5": UC_PPC_REG_FPR5,
57+
"f6": UC_PPC_REG_FPR6,
58+
"f7": UC_PPC_REG_FPR7,
59+
"f8": UC_PPC_REG_FPR8,
60+
"f9": UC_PPC_REG_FPR9,
61+
"f10": UC_PPC_REG_FPR10,
62+
"f11": UC_PPC_REG_FPR11,
63+
"f12": UC_PPC_REG_FPR12,
64+
"f13": UC_PPC_REG_FPR13,
65+
"f14": UC_PPC_REG_FPR14,
66+
"f15": UC_PPC_REG_FPR15,
67+
"f16": UC_PPC_REG_FPR16,
68+
"f17": UC_PPC_REG_FPR17,
69+
"f18": UC_PPC_REG_FPR18,
70+
"f19": UC_PPC_REG_FPR19,
71+
"f20": UC_PPC_REG_FPR20,
72+
"f21": UC_PPC_REG_FPR21,
73+
"f22": UC_PPC_REG_FPR22,
74+
"f23": UC_PPC_REG_FPR23,
75+
"f24": UC_PPC_REG_FPR24,
76+
"f25": UC_PPC_REG_FPR25,
77+
"f26": UC_PPC_REG_FPR26,
78+
"f27": UC_PPC_REG_FPR27,
79+
"f28": UC_PPC_REG_FPR28,
80+
"f29": UC_PPC_REG_FPR29,
81+
"f30": UC_PPC_REG_FPR30,
82+
"f31": UC_PPC_REG_FPR31,
83+
}
84+
85+
class MSR(IntEnum):
86+
SF = 1 << 63
87+
TAG = 1 << 62
88+
ISF = 1 << 61
89+
HV = 1 << 60
90+
TS0 = 1 << 34
91+
TS1 = 1 << 33
92+
TM = 1 << 32
93+
CM = 1 << 31
94+
ICM = 1 << 30
95+
GS = 1 << 28
96+
UCLE = 1 << 26
97+
VR = 1 << 25
98+
SPE = 1 << 25
99+
AP = 1 << 23
100+
VSX = 1 << 23
101+
SA = 1 << 22
102+
KEY = 1 << 19
103+
POW = 1 << 18
104+
TGPR = 1 << 17
105+
CE = 1 << 17
106+
ILE = 1 << 16
107+
EE = 1 << 15
108+
PR = 1 << 14
109+
FP = 1 << 13
110+
ME = 1 << 12
111+
FE0 = 1 << 11
112+
SE = 1 << 10
113+
DWE = 1 << 10
114+
UBLE = 1 << 10
115+
BE = 1 << 9
116+
DE = 1 << 9
117+
FE1 = 1 << 8
118+
AL = 1 << 7
119+
EP = 1 << 6
120+
IR = 1 << 5
121+
DR = 1 << 4
122+
IS = 1 << 5
123+
DS = 1 << 4
124+
PE = 1 << 3
125+
PX = 1 << 2
126+
PMM = 1 << 2
127+
RI = 1 << 1
128+
LE = 1 << 0

qiling/arch/utils.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
from os.path import basename
1212
from functools import lru_cache
1313

14-
from keystone import (Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_X86,
15-
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
14+
from keystone import (Ks, KS_ARCH_ARM, KS_ARCH_ARM64, KS_ARCH_MIPS, KS_ARCH_X86, KS_ARCH_PPC,
15+
KS_MODE_ARM, KS_MODE_THUMB, KS_MODE_MIPS32, KS_MODE_PPC32, KS_MODE_16, KS_MODE_32, KS_MODE_64,
1616
KS_MODE_LITTLE_ENDIAN, KS_MODE_BIG_ENDIAN)
1717

1818
from qiling import Qiling
@@ -104,7 +104,8 @@ def assembler(arch: QL_ARCH, endianess: QL_ENDIAN, is_thumb: bool) -> Ks:
104104
QL_ARCH.MIPS : (KS_ARCH_MIPS, KS_MODE_MIPS32 + endian),
105105
QL_ARCH.A8086 : (KS_ARCH_X86, KS_MODE_16),
106106
QL_ARCH.X86 : (KS_ARCH_X86, KS_MODE_32),
107-
QL_ARCH.X8664 : (KS_ARCH_X86, KS_MODE_64)
107+
QL_ARCH.X8664 : (KS_ARCH_X86, KS_MODE_64),
108+
QL_ARCH.PPC : (KS_ARCH_PPC, KS_MODE_PPC32 + KS_MODE_BIG_ENDIAN)
108109
}
109110

110111
if arch in asm_map:

qiling/cc/ppc.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
4+
5+
from qiling.cc import QlCommonBaseCC
6+
7+
from unicorn.ppc_const import (
8+
UC_PPC_REG_3, UC_PPC_REG_4, UC_PPC_REG_5,
9+
UC_PPC_REG_6, UC_PPC_REG_7, UC_PPC_REG_8,
10+
)
11+
12+
13+
class ppc(QlCommonBaseCC):
14+
"""Default calling convention for PPC
15+
First 6 arguments are passed in regs, the rest are passed on the stack.
16+
"""
17+
18+
_retreg = UC_PPC_REG_3
19+
_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
20+
21+
@staticmethod
22+
def getNumSlots(argbits: int):
23+
return 1

qiling/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class QL_ARCH(IntEnum):
2121
CORTEX_M = 109
2222
RISCV = 110
2323
RISCV64 = 111
24+
PPC = 112
2425

2526
class QL_OS(IntEnum):
2627
LINUX = 201

qiling/os/blob/blob.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55

66
from qiling import Qiling
7-
from qiling.cc import QlCC, intel, arm, mips
7+
from qiling.cc import QlCC, intel, arm, mips, riscv, ppc
88
from qiling.const import QL_ARCH, QL_OS
99
from qiling.os.fcall import QlFunctionCall
1010
from qiling.os.os import QlOs
@@ -26,11 +26,14 @@ def __init__(self, ql: Qiling):
2626
self.ql = ql
2727

2828
cc: QlCC = {
29-
QL_ARCH.X86 : intel.cdecl,
30-
QL_ARCH.X8664 : intel.amd64,
31-
QL_ARCH.ARM : arm.aarch32,
32-
QL_ARCH.ARM64 : arm.aarch64,
33-
QL_ARCH.MIPS : mips.mipso32
29+
QL_ARCH.X86 : intel.cdecl,
30+
QL_ARCH.X8664 : intel.amd64,
31+
QL_ARCH.ARM : arm.aarch32,
32+
QL_ARCH.ARM64 : arm.aarch64,
33+
QL_ARCH.MIPS : mips.mipso32,
34+
QL_ARCH.RISCV : riscv.riscv,
35+
QL_ARCH.RISCV64 : riscv.riscv,
36+
QL_ARCH.PPC : ppc.ppc,
3437
}[ql.arch.type](ql.arch)
3538

3639
self.fcall = QlFunctionCall(ql, cc)

qiling/os/linux/function_hook.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ def get_ret_pc(self):
7979
elif self.ql.arch.type == QL_ARCH.ARM64:
8080
return self.ql.arch.regs.x30
8181

82+
# PPC
83+
elif self.ql.arch.type== QL_ARCH.PPC:
84+
return self.ql.arch.regs.lr
85+
8286
# X86
8387
elif self.ql.arch.type == QL_ARCH.X86:
8488
return self.ql.unpack(self.ql.mem.read(self.ql.arch.regs.esp, self.ql.arch.pointersize))
@@ -98,6 +102,10 @@ def context_fixup(self):
98102
elif self.ql.arch.type == QL_ARCH.MIPS:
99103
pass
100104

105+
# PPC
106+
elif self.ql.arch.type== QL_ARCH.PPC:
107+
pass
108+
101109
# ARM64
102110
elif self.ql.arch.type == QL_ARCH.ARM64:
103111
pass
@@ -121,6 +129,10 @@ def set_ret(self, addr):
121129
elif self.ql.arch.type == QL_ARCH.MIPS:
122130
self.ql.arch.regs.ra = addr
123131

132+
# PPC
133+
elif self.ql.arch.type== QL_ARCH.PPC:
134+
self.ql.arch.regs.lr = addr
135+
124136
# ARM64
125137
elif self.ql.arch.type == QL_ARCH.ARM64:
126138
self.ql.arch.stack_write(0, addr)
@@ -173,29 +185,6 @@ def call_enter(self):
173185
else:
174186
self.context_fixup()
175187

176-
def ret(self):
177-
# ARM
178-
if self.ql.arch.type == QL_ARCH.ARM:
179-
self.ql.arch.regs.arch_pc = self.ret_pc
180-
181-
# MIPS32
182-
elif self.ql.arch.type == QL_ARCH.MIPS:
183-
self.ql.arch.regs.arch_pc = self.ret_pc
184-
185-
# ARM64
186-
elif self.ql.arch.type == QL_ARCH.ARM64:
187-
self.ql.arch.regs.arch_pc = self.ret_pc
188-
189-
# X86
190-
elif self.ql.arch.type == QL_ARCH.X86:
191-
self.ql.arch.regs.arch_pc = self.ret_pc
192-
193-
# X8664
194-
elif self.ql.arch.type == QL_ARCH.X8664:
195-
self.ql.arch.regs.arch_pc = self.ret_pc
196-
else:
197-
raise
198-
199188
def call_exit(self):
200189
# if self.ql.arch.type == QL_ARCH.ARM or self.ql.arch.type == QL_ARCH.ARM64:
201190
# self.ql.arch.regs.arch_pc = self.ql.arch.regs.arch_pc + 4
@@ -211,7 +200,7 @@ def call_exit(self):
211200
else:
212201
onexit_cb(self.ql, onexit_userdata)
213202

214-
self.ret()
203+
self.ql.arch.regs.arch_pc = self.ret_pc
215204

216205

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

606+
# PowerPC
607+
elif self.ql.arch.type== QL_ARCH.PPC:
608+
self.GLOB_DAT = 21
609+
self.JMP_SLOT = 22
610+
# nop
611+
ins = b'\x60\x00\x00\x00'
612+
self.add_function_hook = self.add_function_hook_relocation
613+
617614
self._parse()
618615
if self.rel != None:
619616
self.show_relocation(self.rel)

0 commit comments

Comments
 (0)