Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/archinfo/arch_x86.py: 67%

123 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:15 +0000

1from .arch import Arch, register_arch, Endness, Register 

2from .tls import TLSArchInfo 

3from .archerror import ArchError 

4 

5try: 

6 import capstone as _capstone 

7except ImportError: 

8 _capstone = None 

9 

10try: 

11 import keystone as _keystone 

12except ImportError: 

13 _keystone = None 

14 

15try: 

16 import unicorn as _unicorn 

17except ImportError: 

18 _unicorn = None 

19 

20try: 

21 import pyvex as _pyvex 

22except ImportError: 

23 _pyvex = None 

24 

25 

26_NATIVE_FUNCTION_PROLOGS = [ 

27 rb"\x8b\xff\x55\x8b\xec", # mov edi, edi; push ebp; mov ebp, esp 

28 rb"\x55\x8b\xec", # push ebp; mov ebp, esp 

29 rb"\x55\x89\xe5", # push ebp; mov ebp, esp 

30 rb"\x55\x57\x56", # push ebp; push edi; push esi 

31 # mov eax, 0x000000??; (push ebp; push eax; push edi; push ebx; push esi; push edx; push ecx) sub esp 

32 rb"\xb8[\x00-\xff]\x00\x00\x00[\x50\x51\x52\x53\x55\x56\x57]{0,7}\x8b[\x00-\xff]{2}", 

33 # (push ebp; push eax; push edi; push ebx; push esi; push edx; push ecx) sub esp 

34 rb"[\x50\x51\x52\x53\x55\x56\x57]{1,7}\x83\xec[\x00-\xff]{2,4}", 

35 # (push ebp; push eax; push edi; push ebx; push esi; push edx; push ecx) mov xxx, xxx 

36 rb"[\x50\x51\x52\x53\x55\x56\x57]{1,7}\x8b[\x00-\xff]{2}", 

37 rb"(\x81|\x83)\xec", # sub xxx %esp 

38] 

39# every function prolog can potentially be prefixed with endbr32 

40_endbr32 = b"\xf3\x0f\x1e\xfb" 

41_prefixed = [(_endbr32 + prolog) for prolog in _NATIVE_FUNCTION_PROLOGS] 

42_FUNCTION_PROLOGS = _prefixed + _NATIVE_FUNCTION_PROLOGS 

43 

44 

45class ArchX86(Arch): 

46 def __init__(self, endness=Endness.LE): 

47 if endness != Endness.LE: 

48 raise ArchError("Arch i386 must be little endian") 

49 super().__init__(endness) 

50 if self.vex_archinfo: 

51 self.vex_archinfo["x86_cr0"] = 0xFFFFFFFF 

52 

53 # Register blacklist 

54 reg_blacklist = ("cs", "ds", "es", "fs", "gs", "ss", "gdt", "ldt") 

55 if self.reg_blacklist is not None and self.reg_blacklist_offsets is not None: 

56 for register in self.register_list: 

57 if register.name in reg_blacklist: 

58 self.reg_blacklist.append(register.name) 

59 self.reg_blacklist_offsets.append(register.vex_offset) 

60 

61 if _unicorn and _pyvex: 

62 # CPU flag registers 

63 uc_flags_reg = _unicorn.x86_const.UC_X86_REG_EFLAGS 

64 cpu_flag_registers = {"d": 1 << 10, "ac": 1 << 18, "id": 1 << 21} 

65 for reg, reg_bitmask in cpu_flag_registers.items(): 

66 reg_offset = self.get_register_offset(reg) 

67 self.cpu_flag_register_offsets_and_bitmasks_map[reg_offset] = (uc_flags_reg, reg_bitmask) 

68 

69 mxcsr_registers = {"sseround": 1 << 14 | 1 << 13} 

70 uc_mxcsr_reg = _unicorn.x86_const.UC_X86_REG_MXCSR 

71 for reg, reg_bitmask in mxcsr_registers.items(): 

72 reg_offset = self.get_register_offset(reg) 

73 self.cpu_flag_register_offsets_and_bitmasks_map[reg_offset] = (uc_mxcsr_reg, reg_bitmask) 

74 

75 @property 

76 def capstone_x86_syntax(self): 

77 """ 

78 Get the current syntax Capstone uses for x86. It can be 'intel' or 'at&t' 

79 

80 :return: Capstone's current x86 syntax 

81 :rtype: str 

82 """ 

83 

84 return self._cs_x86_syntax 

85 

86 @capstone_x86_syntax.setter 

87 def capstone_x86_syntax(self, new_syntax): 

88 """ 

89 Set the syntax that Capstone outputs for x86. 

90 """ 

91 

92 if new_syntax not in ("intel", "at&t"): 

93 raise ArchError('Unsupported Capstone x86 syntax. It must be either "intel" or "at&t".') 

94 

95 if new_syntax != self._cs_x86_syntax: 

96 self._cs = None 

97 self._cs_x86_syntax = new_syntax 

98 

99 def _configure_capstone(self): 

100 self._cs.syntax = ( 

101 _capstone.CS_OPT_SYNTAX_ATT if self._cs_x86_syntax == "at&t" else _capstone.CS_OPT_SYNTAX_INTEL 

102 ) 

103 

104 @property 

105 def keystone_x86_syntax(self): 

106 """ 

107 Get the current syntax Keystone uses for x86. It can be 'intel', 

108 'at&t', 'nasm', 'masm', 'gas' or 'radix16' 

109 

110 :return: Keystone's current x86 syntax 

111 :rtype: str 

112 """ 

113 

114 return self._ks_x86_syntax 

115 

116 @keystone_x86_syntax.setter 

117 def keystone_x86_syntax(self, new_syntax): 

118 """ 

119 Set the syntax that Keystone uses for x86. 

120 """ 

121 

122 if new_syntax not in ("intel", "at&t", "nasm", "masm", "gas", "radix16"): 

123 raise ArchError( 

124 "Unsupported Keystone x86 syntax. It must be one of the following: " 

125 '"intel", "at&t", "nasm", "masm", "gas" or "radix16".' 

126 ) 

127 

128 if new_syntax != self._ks_x86_syntax: 

129 self._ks = None 

130 self._ks_x86_syntax = new_syntax 

131 

132 def _configure_keystone(self): 

133 if self._ks_x86_syntax == "at&t": 

134 self._ks.syntax = _keystone.KS_OPT_SYNTAX_ATT 

135 elif self._ks_x86_syntax == "nasm": 

136 self._ks.syntax = _keystone.KS_OPT_SYNTAX_NASM 

137 elif self._ks_x86_syntax == "masm": 

138 self._ks.syntax = _keystone.KS_OPT_SYNTAX_MASM 

139 elif self._ks_x86_syntax == "gas": 

140 self._ks.syntax = _keystone.KS_OPT_SYNTAX_GAS 

141 elif self._ks_x86_syntax == "radix16": 

142 self._ks.syntax = _keystone.KS_OPT_SYNTAX_RADIX16 

143 else: 

144 self._ks.syntax = _keystone.KS_OPT_SYNTAX_INTEL 

145 

146 bits = 32 

147 vex_arch = "VexArchX86" 

148 name = "X86" 

149 qemu_name = "i386" 

150 ida_processor = "metapc" 

151 linux_name = "i386" 

152 triplet = "i386-linux-gnu" 

153 max_inst_bytes = 15 

154 call_sp_fix = -4 

155 ret_offset = 8 

156 vex_conditional_helpers = True 

157 syscall_num_offset = 8 

158 call_pushes_ret = True 

159 stack_change = -4 

160 memory_endness = Endness.LE 

161 register_endness = Endness.LE 

162 sizeof = {"short": 16, "int": 32, "long": 32, "long long": 64} 

163 if _capstone: 

164 cs_arch = _capstone.CS_ARCH_X86 

165 cs_mode = _capstone.CS_MODE_32 + _capstone.CS_MODE_LITTLE_ENDIAN 

166 _cs_x86_syntax = None # Set it to 'att' in order to use AT&T syntax for x86 

167 if _keystone: 

168 ks_arch = _keystone.KS_ARCH_X86 

169 ks_mode = _keystone.KS_MODE_32 + _keystone.KS_MODE_LITTLE_ENDIAN 

170 _ks_x86_syntax = None 

171 uc_arch = _unicorn.UC_ARCH_X86 if _unicorn else None 

172 uc_mode = (_unicorn.UC_MODE_32 + _unicorn.UC_MODE_LITTLE_ENDIAN) if _unicorn else None 

173 uc_const = _unicorn.x86_const if _unicorn else None 

174 uc_prefix = "UC_X86_" if _unicorn else None 

175 function_prologs = _FUNCTION_PROLOGS 

176 function_epilogs = { 

177 rb"\xc9\xc3", # leave; ret 

178 rb"([^\x41][\x50-\x5f]{1}|\x41[\x50-\x5f])\xc3", # pop <reg>; ret 

179 rb"[^\x48][\x83,\x81]\xc4([\x00-\xff]{1}|[\x00-\xff]{4})\xc3", # add esp, <siz>; retq 

180 } 

181 ret_instruction = b"\xc3" 

182 nop_instruction = b"\x90" 

183 instruction_alignment = 1 

184 register_list = [ 

185 Register( 

186 name="eax", 

187 size=4, 

188 subregisters=[("ax", 0, 2), ("al", 0, 1), ("ah", 1, 1)], 

189 general_purpose=True, 

190 argument=True, 

191 linux_entry_value=0x1C, 

192 ), 

193 Register( 

194 name="ecx", 

195 size=4, 

196 subregisters=[("cx", 0, 2), ("cl", 0, 1), ("ch", 1, 1)], 

197 general_purpose=True, 

198 argument=True, 

199 ), 

200 Register( 

201 name="edx", 

202 size=4, 

203 subregisters=[("dx", 0, 2), ("dl", 0, 1), ("dh", 1, 1)], 

204 general_purpose=True, 

205 argument=True, 

206 linux_entry_value="ld_destructor", 

207 ), 

208 Register( 

209 name="ebx", 

210 size=4, 

211 subregisters=[("bx", 0, 2), ("bl", 0, 1), ("bh", 1, 1)], 

212 general_purpose=True, 

213 argument=True, 

214 ), 

215 Register( 

216 name="esp", 

217 size=4, 

218 alias_names=("sp",), 

219 general_purpose=True, 

220 default_value=(Arch.initial_sp, True, "global"), 

221 ), 

222 Register(name="ebp", size=4, alias_names=("bp",), general_purpose=True, argument=True, linux_entry_value=0), 

223 Register( 

224 name="esi", 

225 size=4, 

226 subregisters=[("si", 0, 2), ("sil", 0, 1), ("sih", 1, 1)], 

227 general_purpose=True, 

228 argument=True, 

229 ), 

230 Register( 

231 name="edi", 

232 size=4, 

233 subregisters=[("di", 0, 2), ("dil", 0, 1), ("dih", 1, 1)], 

234 general_purpose=True, 

235 argument=True, 

236 ), 

237 Register(name="cc_op", size=4, default_value=(0, False, None), concrete=False, artificial=True), 

238 Register(name="cc_dep1", size=4, concrete=False, artificial=True), 

239 Register(name="cc_dep2", size=4, concrete=False, artificial=True), 

240 Register(name="cc_ndep", size=4, concrete=False, artificial=True), 

241 Register(name="d", size=4, alias_names=("dflag",), default_value=(1, False, None), concrete=False), 

242 Register(name="id", size=4, alias_names=("idflag",), default_value=(1, False, None), concrete=False), 

243 Register(name="ac", size=4, alias_names=("acflag",), default_value=(0, False, None), concrete=False), 

244 Register(name="eip", size=4, alias_names=("ip", "pc")), 

245 Register( 

246 name="fpreg", 

247 size=64, 

248 subregisters=[ 

249 ("mm0", 0, 8), 

250 ("mm1", 8, 8), 

251 ("mm2", 16, 8), 

252 ("mm3", 24, 8), 

253 ("mm4", 32, 8), 

254 ("mm5", 40, 8), 

255 ("mm6", 48, 8), 

256 ("mm7", 56, 8), 

257 ], 

258 alias_names=("fpu_regs",), 

259 floating_point=True, 

260 concrete=False, 

261 ), 

262 Register(name="fptag", size=8, alias_names=("fpu_tags",), floating_point=True, default_value=(0, False, None)), 

263 Register(name="fpround", size=4, floating_point=True, default_value=(0, False, None)), 

264 Register(name="fc3210", size=4, floating_point=True), 

265 Register(name="ftop", size=4, floating_point=True, default_value=(7, False, None), artificial=True), 

266 Register(name="sseround", size=4, vector=True, default_value=(0, False, None)), 

267 Register(name="xmm0", size=16, vector=True), 

268 Register(name="xmm1", size=16, vector=True), 

269 Register(name="xmm2", size=16, vector=True), 

270 Register(name="xmm3", size=16, vector=True), 

271 Register(name="xmm4", size=16, vector=True), 

272 Register(name="xmm5", size=16, vector=True), 

273 Register(name="xmm6", size=16, vector=True), 

274 Register(name="xmm7", size=16, vector=True), 

275 Register(name="cs", size=2), 

276 Register(name="ds", size=2), 

277 Register(name="es", size=2), 

278 Register(name="fs", size=2, default_value=(0, False, None), concrete=False), 

279 Register(name="gs", size=2, default_value=(0, False, None), concrete=False), 

280 Register(name="ss", size=2), 

281 Register(name="ldt", size=8, default_value=(0, False, None), concrete=False), 

282 Register(name="gdt", size=8, default_value=(0, False, None), concrete=False), 

283 Register(name="emnote", size=4, artificial=True), 

284 Register(name="cmstart", size=4), 

285 Register(name="cmlen", size=4), 

286 Register(name="nraddr", size=4), 

287 Register(name="sc_class", size=4), 

288 Register(name="ip_at_syscall", size=4, concrete=False, artificial=True), 

289 ] 

290 

291 symbol_type_translation = {10: "STT_GNU_IFUNC", "STT_LOOS": "STT_GNU_IFUNC"} 

292 lib_paths = ["/lib32", "/usr/lib32"] 

293 got_section_name = ".got.plt" 

294 ld_linux_name = "ld-linux.so.2" 

295 elf_tls = TLSArchInfo(2, 56, [8], [4], [0], 0, 0) 

296 dwarf_registers = [ 

297 "eax", 

298 "ecx", 

299 "edx", 

300 "ebx", 

301 "esp", 

302 "ebp", 

303 "esi", 

304 "edi", 

305 "eip", 

306 "eflags", 

307 "<none>", 

308 "st0", 

309 "st1", 

310 "st2", 

311 "st3", 

312 "st4", 

313 "st5", 

314 "st6", 

315 "st7", 

316 "<none>", 

317 "<none>", 

318 "xmm0", 

319 "xmm1", 

320 "xmm2", 

321 "xmm3", 

322 "xmm4", 

323 "xmm5", 

324 "xmm6", 

325 "xmm7", 

326 "mm0", 

327 "mm1", 

328 "mm2", 

329 "mm3", 

330 "mm4", 

331 "mm5", 

332 "mm6", 

333 "mm7", 

334 "fcw", 

335 "fsw", 

336 "mxcsr", 

337 "es", 

338 "cs", 

339 "ss", 

340 "ds", 

341 "fs", 

342 "gs", 

343 "<none>", 

344 "<none>", 

345 "tr", 

346 "ldtr", 

347 ] 

348 

349 

350register_arch([r".*i?\d86|.*x32|.*x86|.*metapc"], 32, Endness.LE, ArchX86)