Skip to content

Commit 79da526

Browse files
author
Justin Sherman
committed
Bug fixes, CryptDecrypt, CryptDeriveKey, SetWindowLong
1 parent 7834129 commit 79da526

File tree

6 files changed

+131
-2
lines changed

6 files changed

+131
-2
lines changed

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ capstone
33
lznt1
44
unicorn==1.0.2
55
jsonschema
6+
pycryptodome

speakeasy/binemu.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ def read_mem_string(self, address, width=1, max_chars=0):
686686
i = 0
687687

688688
if width == 1:
689-
decode = 'utf-8'
689+
decode = 'latin1'
690690
elif width == 2:
691691
decode = 'utf-16le'
692692
else:

speakeasy/windows/winemu.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ def map_pe(self, pe, mod_name='none', emu_path=''):
671671
"""
672672
Map the specified PE into the emulation space
673673
"""
674-
image_size = len(pe.mapped_image)
674+
image_size = pe.image_size
675675
base = pe.base
676676
ranges = self.get_valid_ranges(image_size, addr=base)
677677
base, size = ranges
@@ -1932,6 +1932,8 @@ def _dispatch_seh_x86(self, except_code):
19321932
"registers": regs,
19331933
})
19341934

1935+
# EBX clobber, -1 is what I observed inside a VM
1936+
self.reg_write(_arch.X86_REG_EBX, 0xffffffff)
19351937
self.set_pc(entry.Handler)
19361938
return True
19371939
return False
@@ -1954,6 +1956,15 @@ def _continue_seh_x86(self):
19541956
if seh.handler_ret_val is None:
19551957
seh.handler_ret_val = ret_val
19561958

1959+
ctx = seh.get_context()
1960+
1961+
if seh.context_address:
1962+
ctx = self.mem_cast(ctx, seh.context_address)
1963+
1964+
# Always restore thread context, is it correct to always
1965+
# do this?
1966+
self.load_thread_context(ctx)
1967+
19571968
for frame in seh.get_frames():
19581969
if not frame.searched:
19591970
seh.set_current_frame(frame)

speakeasy/winenv/api/usermode/advapi32.py

+96
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import speakeasy.windows.objman as objman
1010

1111
from .. import api
12+
from Crypto.Cipher import ARC4
1213
import hashlib
1314

1415
SERVICE_STATUS_HANDLE_BASE = 0x1000
@@ -35,6 +36,8 @@ def __init__(self, emu):
3536
self.curr_handle = 0x2800
3637
self.service_status_handle = SERVICE_STATUS_HANDLE_BASE
3738

39+
self.rc4 = None
40+
3841
super(AdvApi32, self).__get_hook_attrs__(self)
3942

4043
def get_handle(self):
@@ -1113,6 +1116,99 @@ def CryptDestroyHash(self, emu, argv, ctx={}):
11131116

11141117
return 1
11151118

1119+
@apihook('CryptDeriveKey', argc=5)
1120+
def CryptDeriveKey(self, emu, argv, ctx={}):
1121+
"""
1122+
BOOL CryptDeriveKey(
1123+
HCRYPTPROV hProv,
1124+
ALG_ID Algid,
1125+
HCRYPTHASH hBaseData,
1126+
DWORD dwFlags,
1127+
HCRYPTKEY *phKey
1128+
);
1129+
"""
1130+
1131+
hProv, Algid, hBaseData, dwFlags, phKey = argv
1132+
1133+
# Only RC4 supported right now
1134+
if Algid != 0x6801:
1135+
return 0
1136+
1137+
hnd = self.hash_objects.get(hBaseData, None)
1138+
1139+
if hnd is None:
1140+
emu.set_last_error(windefs.ERROR_INVALID_HANDLE)
1141+
return 0
1142+
1143+
# CryptDeriveKey zeroes out the last 11 bytes of the hash,
1144+
# so we gotta do the same before it is written to the
1145+
# phKey structure
1146+
fixed_digest = hnd.digest()[:5] + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
1147+
1148+
ptrsz = emu.get_ptr_size()
1149+
1150+
hKey = self.win.HCRYPTKEY(ptrsz)
1151+
hKey.Algid = Algid
1152+
hKey.keylen = hnd.digest_size
1153+
hKey.keyp = self.mem_alloc(hKey.keylen)
1154+
1155+
hKeyp = self.mem_alloc(hKey.sizeof())
1156+
1157+
self.mem_write(hKey.keyp, fixed_digest)
1158+
1159+
self.mem_write(hKeyp, hKey.get_bytes())
1160+
self.mem_write(phKey, hKeyp.to_bytes(ptrsz, "little"))
1161+
1162+
return 1
1163+
1164+
@apihook('CryptDecrypt', argc=6)
1165+
def CryptDecrypt(self, emu, argv, ctx={}):
1166+
"""
1167+
BOOL CryptDecrypt(
1168+
HCRYPTKEY hKey,
1169+
HCRYPTHASH hHash,
1170+
BOOL Final,
1171+
DWORD dwFlags,
1172+
BYTE *pbData,
1173+
DWORD *pdwDataLen
1174+
);
1175+
"""
1176+
1177+
hKey, hHash, Final, dwFlags, pbData, pdwDataLen = argv
1178+
1179+
# Hashing not supported
1180+
if hHash:
1181+
return 0
1182+
1183+
ptrsz = emu.get_ptr_size()
1184+
1185+
hKey = self.mem_cast(self.win.HCRYPTKEY(ptrsz), hKey)
1186+
1187+
# Only RC4 supported right now
1188+
if hKey.Algid != 0x6801:
1189+
return 0
1190+
1191+
encdatalen_b = self.mem_read(pdwDataLen, 4)
1192+
encdatalen = int.from_bytes(encdatalen_b, "little")
1193+
1194+
encdata = self.mem_read(pbData, encdatalen)
1195+
1196+
key = self.mem_read(hKey.keyp, hKey.keylen)
1197+
1198+
if self.rc4 is None:
1199+
self.rc4 = ARC4.new(key)
1200+
1201+
dec = self.rc4.decrypt(encdata)
1202+
declen = len(dec)
1203+
1204+
self.mem_write(pbData, dec)
1205+
self.mem_write(pdwDataLen, int.to_bytes(declen, 4, "little"))
1206+
1207+
if Final == True:
1208+
self.rc4 = None
1209+
1210+
return 1
1211+
11161212
@apihook('RegGetValue', argc=7, conv=_arch.CALL_CONV_STDCALL)
11171213
def RegGetValue(self, emu, argv, ctx={}):
11181214
'''

speakeasy/winenv/api/usermode/user32.py

+13
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,19 @@ def GetWindowLong(self, emu, argv, ctx={}):
795795

796796
return rv
797797

798+
@apihook('SetWindowLong', argc=3)
799+
def SetWindowLong(self, emu, argv, ctx={}):
800+
"""
801+
LONG SetWindowLongA(
802+
HWND hWnd,
803+
int nIndex,
804+
LONG dwNewLong
805+
);
806+
"""
807+
808+
809+
return 1
810+
798811
@apihook('DialogBoxParam', argc=5)
799812
def DialogBoxParam(self, emu, argv, ctx={}):
800813
'''

speakeasy/winenv/defs/windows/advapi32.py

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (C) 2020 FireEye, Inc. All Rights Reserved.
22

33
from speakeasy.struct import EmuStruct, Ptr
4+
import ctypes as ct
45

56
NTE_BAD_ALGID = 0x80090008
67

@@ -15,6 +16,13 @@ def __init__(self, ptr_size):
1516
self.lpServiceName = Ptr
1617
self.lpServiceProc = Ptr
1718

19+
class HCRYPTKEY(EmuStruct):
20+
def __init__(self, ptr_size):
21+
super().__init__(ptr_size)
22+
self.Algid = ct.c_uint32
23+
self.keylen = ct.c_uint32
24+
self.keyp = Ptr
25+
1826

1927
def get_define_int(define, prefix=''):
2028
for k, v in globals().items():

0 commit comments

Comments
 (0)