1. SAMPLE
2. Static analysis
- Hàm main:
- Có vẻ IDA dịch không rõ lắm, xem lại asm:
-
Có vẻ hàm lấy giá trị trên cùng của stack + 0x35
-
Note:
Khi chương trình gọi lệnh call một hàm thì giá trị trên cùng của stack sẽ lưu địa chỉ của instruction tiếp theo.
-> Có nghĩa lấy địa chỉ của pop edi
là 0xD042F1
+ 0x35
.
- Debug thử:
-> Đúng là như vậy.
- Sau khi tính toán được giá trị mới thì chương trình nhảy đến địa chỉ đó luôn:
-> Tới đây ta có thể patch lại bằng cách tự tính toán địa chỉ và thay thể lệnh call
bằng jump
.
-
Có thể dùng tool keypatch để patch lại cho dễ.
-
Kéo tiếp xuống dưới lại gặp hàm tương tự nên ta cũng thực hiện tương tự cuối cùng có thể có thể decompile được hàm main:
3. Patch anti-analysis
-
Đi sâu vào hàm main ta bắt gặp kĩ thuật tương tự và rất nhiều nên không thể patch lại bằng tay toàn bộ được.
-
Để ý các các chỗ obfuscate đó đều có dạng như sau:
-> Có thể dựa vào để tìm và patch lại các chỗ bị obfuscate
import re
from pwn import *
data= open("PLAY_ransom.exe", "rb").read()
regex = b'\x06\x81\xC4....\x83\xC4.\xE8....'
count=0
for match in re.finditer(regex, data):
count += 1
next_ins_addr = match.start()+15 # ins addr after call ins
bytes_matched= match.group()
func_called_addr=u32(bytes_matched[bytes_matched.find(b'\xe8')+1:])+next_ins_addr
add_val=data[func_called_addr+3]
#jmp_addr=next_ins_addr+add_val
patch_addr=next_ins_addr-5
#patch
data1=list(data)
data1[patch_addr:patch_addr+5]=list(b'\xe9'+p8(add_val)+b'\x00'*3) #change call =jmp
data=bytes(data1)
pat=open("patched.exe", "wb")
pat.write(data)
print("[+]Done")
4. API hashing
- Quan sát
sub_40C750
:
-
Ta thấy có rất nhiều hàm như vậy và mỗi hàm đều có hằng số đưa vào, dựa trên kinh nghiệm mấy bài trước khá chắc đây là kĩ thuật
API hashing
-
Xem hàm thử:
-
Chương trình lấy
API_name
rồi tính hash rồi so sánh với giá trị ban đầu đưa vào. -
Hàm
calculate_hash
sử dụng bằng phép tính toán gì đó rất dài nên không thể nào viết lại bằng python rồi tính hash được.
-> Debug cũng không được vì chỉ có thể debug được đối với binary ban đầu
còn binary sau khi patch
không biết sao lại lỗi:
-> Nhưng khi debug đối với cái ban đầu thì không đơn giản là đặp bp tại đó rồi debug vì khi đó chương trình sẽ nhảy vào code rác của obfuscate và gây crash chương trình -> bắt buộc phải đặt bp tại main
rồi step
từ từ cho chương trình tự deobfuscate tới khi nào đến chỗ cần xem -> rất mất thời gian.
Emulate calculate_hash dùng unicorn
-> Chỉ cần emulate code của hàm calculate_hash
rồi đưa vào các tham số phù hợp là được.
- Extract code của hàm
calculate_hash
:
import idaapi, idc
func_addr = idc.get_name_ea_simple("calculate_hash")
func = idaapi.get_func(func_addr)
func_OPCODE = idaapi.get_bytes(func.start_ea, func.size())
print(func_OPCODE)
-> Lưu ý bỏ byte \xc3
(ret) ở cuối để unicorn
chạy được
-> Ta tạo một list lưu các API
để brute dựa trên giá trị hash API_list.txt
import json
json_data=json.loads(open("API_list.txt", "rb").read())
API_names=json_data['exports']
hash_vals=[3196191668, 587706791, 430125299, 745928694, 3310323133, 2538134804, 2160950796, 3321973177, 2119526180, 2016564646, 819148513, 2706107229, 2274961481, 4009797727, 2329007555, 1515022974, 4070557793, 3184347727, 3230171373, 1150531511, 2458654477, 1274182115, 2607238143, 1002302808, 2229935675, 3774275279, 2276756918, 3884594833, 2318578073, 1560409820, 3301358813, 922136913, 2092703519, 2554527287, 2432991358, 3496982552, 373201559, 1243518349, 4110329759, 3017027465, 65123382, 1513489892, 1081677820, 711108549, 2797954528, 199922510, 1914963876, 1145734755, 1493453468, 791102906, 3656038948, 1967849689, 57836566, 1700271275, 2941172387, 1965304112, 3919218989, 470098108, 333447649, 1590973787, 1777329460, 2419093438, 2261379902, 1660342600, 1434042011, 2363481290, 2480380205, 804062357, 2152398498, 2541341025, 1101559834, 689679891, 1248996702, 2088540052, 1497197006, 335155875, 969247798, 3560560371, 851486428, 2185952081, 429295890]
from unicorn import *
from unicorn.x86_const import *
import struct
def EMULATE(inBuff:bytes) -> Uc:
# ------------------Initialization ------------------
# remove "retn" instruction from SHA1Hash function opcodes or -> UC_ERR_FETCH_UNMAPPED -> no ret address on stack
CALCULATE_HASH_OPCODE = b"U\x8b\xec\x83\xec V\x8b\xc2\x89M\xfc3\xf6\x89E\xe0W\x8b\xf8\x85\xc9u\x1b\x8bM\x08\x81\xc1\xb1gV\x16\x8b\xc1\xc1\xe8\x0f3\xc1i\xc8w\xca\xeb\x85\xe9\x07\x02\x00\x00S\x83\xf8\x10\x0f\x82j\x01\x00\x00\x8b]\x08\x8d\x93(D#$\x89U\xe8\x8d\x83O\x86\xc8a\x8d\x93w\xca\xeb\x85\x89U\xec\x8dQ\x03\x89U\xf8\x8dQ\x02A\x89U\xf4\x8bU\xf8\x89M\xf0\x8b\xcf\xc1\xe9\x04\x89M\xe4\x0f\xb6\x142\x83\xef\x10\x8bM\xf4\xc1\xe2\x08\x0f\xb6\x0c1\x0b\xd1\x8bM\xf0\xc1\xe2\x08\x0f\xb6\x0c1\x0b\xd1\x8bM\xfc\xc1\xe2\x08\x0f\xb6\x0c\x0e\x0b\xd1i\xca\x895\x14z\x8bU\xe8+\xd1\x8bM\xf8\xc1\xc2\ri\xd2\xb1y7\x9e\x89U\xe8\x0f\xb6T1\x04\x8bM\xf4\xc1\xe2\x08\x0f\xb6L1\x04\x0b\xd1\x8bM\xf0\xc1\xe2\x08\x0f\xb6L1\x04\x0b\xd1\x8bM\xfc\xc1\xe2\x08\x0f\xb6L\x0e\x04\x0b\xd1i\xca\x895\x14z\x8bU\xec+\xd1\x8bM\xf8\xc1\xc2\ri\xd2\xb1y7\x9e\x89U\xec\x0f\xb6T1\x08\x8bM\xf4\xc1\xe2\x08\x0f\xb6L1\x08\x0b\xd1\x8bM\xf0\xc1\xe2\x08\x0f\xb6L1\x08\x0b\xd1\x8bM\xfc\xc1\xe2\x08\x0f\xb6L\x0e\x08\x0b\xd1i\xca\x895\x14z+\xd9\x8bM\xf8\xc1\xc3\ri\xdb\xb1y7\x9e\x0f\xb6T1\x0c\x8bM\xf4\xc1\xe2\x08\x0f\xb6L1\x0c\x0b\xd1\x8bM\xf0\xc1\xe2\x08\x0f\xb6L1\x0c\x0b\xd1\x8bM\xfc\xc1\xe2\x08\x0f\xb6L\x0e\x0c\x83\xc6\x10\x0b\xd1i\xca\x895\x14z\x8bU\xf8+\xc1\xc1\xc0\ri\xc0\xb1y7\x9e\x83m\xe4\x01\x0f\x85\xe8\xfe\xff\xff\x8bU\xec\x8bM\xfc\xc1\xc8\x0e\xc1\xc3\x0c\xc1\xc2\x07\x03\xc3\x03\xc2\x8bU\xe8\xd1\xc2\x03\xc2\xeb\x08\x8bE\x08\x05\xb1gV\x16\x03E\xe0\x83\xff\x04rP\x8b\xdf\xc1\xeb\x02\xeb\x05f\x90\x8bM\xfc\x0f\xb6T1\x03\x83\xef\x04\x0f\xb6L1\x02\xc1\xe2\x08\x0b\xd1\x8bM\xfc\xc1\xe2\x08\x0f\xb6L1\x01\x0b\xd1\x8bM\xfc\xc1\xe2\x08\x0f\xb6\x0c1\x83\xc6\x04\x0b\xd1i\xca\xc3QM=+\xc1\xc1\xc8\x0fi\xc0/\xeb\xd4'\x83\xeb\x01u\xb9[\x85\xfft!\x8bU\xfc\x03\xd6\x0f\xb6\n\x8dR\x01i\xc9\xb1gV\x16\x03\xc8\xc1\xc1\x0bi\xc1\xb1y7\x9e\x83\xef\x01u\xe4\x8b\xc8\xc1\xe9\x0f3\xc8i\xc9w\xca\xeb\x85\x8b\xc1\xc1\xe8\r3\xc1i\xc8=\xae\xb2\xc2_^\x8b\xc1\xc1\xe8\x103\xc1\x8b\xe5]"
OPCODE_ADDRESS = 0x400000
API_LEN = len(inBuff)
CONSTVAL = 1
BUFFERADDR = OPCODE_ADDRESS + 0x200000
# ------------------ Setting + Starting Emulator ------------------
try:
mu = Uc(UC_ARCH_X86, UC_MODE_32) # set EMU architecture and mode
mu.mem_map(OPCODE_ADDRESS, 0x200000, UC_PROT_ALL) # map memory for SHA1Hash function opcodes, stack etc.
mu.mem_write(OPCODE_ADDRESS, CALCULATE_HASH_OPCODE) # write opcodes to memory
mu.mem_map(BUFFERADDR, 0x1000, UC_PROT_ALL) # map memory for input to be hashed
mu.mem_write(BUFFERADDR, inBuff) # write input bytes to memory
mu.reg_write(UC_X86_REG_ESP, OPCODE_ADDRESS + 0x100000) # initialize stack (ESP)
mu.reg_write(UC_X86_REG_EBP, OPCODE_ADDRESS + 0x100000) # initialize frame pointer (EBP) # set EAX register (argument) -> CONSTVAL
mu.mem_write(OPCODE_ADDRESS + 0x100000+4, struct.pack("<I", 1))
mu.reg_write(UC_X86_REG_EDX, API_LEN)
mu.reg_write(UC_X86_REG_ECX, BUFFERADDR)
mu.emu_start(OPCODE_ADDRESS, OPCODE_ADDRESS + len(CALCULATE_HASH_OPCODE))
return mu
except UcError as e:
print("ERROR: %s" % e)
res={}
for val in hash_vals:
for api in API_names:
mu = EMULATE(api.encode())
if (mu.reg_read(UC_X86_REG_EAX)+0x4E986790)&0xffffffff == val:
res[val]=api
break
print(res)
- Kết quả:
xx={3196191668: 'LoadLibraryA', 587706791: 'VirtualAlloc', 430125299: 'VirtualFree', 745928694: 'FindFirstFileW', 3310323133: 'FindNextFileW', 2538134804: 'FindClose', 2160950796: 'CreateFileA', 3321973177: 'CreateFileW', 2119526180: 'ReadFile', 2016564646: 'WriteFile', 819148513: 'SetFilePointer', 2706107229: 'WaitForMultipleObjects', 2274961481: 'WaitForSingleObject', 4009797727: 'CreateThread', 2329007555: 'GetFileAttributesW', 1515022974: 'GetFileAttributesA', 4070557793: 'GetModuleFileNameA', 3184347727: 'GetCurrentProcess', 3230171373: 'CloseHandle',1150531511: 'GetWindowsDirectoryA', 2458654477: 'Sleep', 1274182115: 'GetFileSizeEx', 2607238143: 'GetDriveTypeW', 1002302808: 'SetFilePointerEx', 2229935675: 'SetFileAttributesW', 3774275279: 'HeapFree', 2276756918: 'GetProcessHeap', 3884594833: 'GetLogicalDriveStringsW', 2318578073: 'GetDiskFreeSpaceExW', 1560409820: 'FindFirstVolumeW', 3301358813: 'GetVolumePathNamesForVolumeNameW', 922136913:'FindNextVolumeW', 2092703519: 'FindVolumeClose', 2554527287: 'SetVolumeMountPointW', 2432991358: 'GetTempPathW', 3496982552: 'MoveFileW', 373201559: 'VirtualProtect', 1243518349: 'K32EnumProcessModules', 4110329759: 'K32EnumProcessModulesEx', 3017027465: 'K32GetModuleFileNameExA', 65123382: 'GetCommandLineW', 1513489892: 'CreateDirectoryW', 1081677820: 'GetTickCount', 711108549: 'GetModuleFileNameW', 2797954528: 'GetFileSize', 199922510: 'GetWindowsDirectoryW', 1914963876: 'CopyFileW', 1145734755: 'RtlInitializeCriticalSection', 1493453468: 'RtlDeleteCriticalSection', 791102906: 'RtlEnterCriticalSection', 3656038948: 'RtlLeaveCriticalSection', 1967849689: 'RtlAllocateHeap', 57836566: 'BCryptOpenAlgorithmProvider', 1700271275: 'BCryptCloseAlgorithmProvider', 2941172387: 'BCryptGenerateSymmetricKey', 1965304112: 'BCryptSetProperty', 3919218989: 'BCryptGenRandom', 470098108: 'BCryptDestroyKey', 333447649: 'BCryptEncrypt', 1590973787: 'BCryptExportKey', 1777329460: 'BCryptImportKeyPair', 2419093438: 'NetShareEnum', 2261379902:'NetApiBufferFree', 1660342600: 'IcmpCreateFile', 1434042011: 'IcmpCloseHandle', 2363481290: 'GetAdaptersInfo', 2480380205: 'IcmpSendEcho2', 804062357: 'InetNtopW', 2152398498: 'inet_ntop', 2541341025: 'WSAStartup', 1101559834: 'WSACleanup', 689679891: 'inet_addr', 1248996702: 'socket', 2088540052: 'htons', 1497197006: 'connect', 335155875: 'closesocket', 969247798: 'CommandLineToArgvW', 3560560371: 'WNetAddConnection2W', 851486428: 'WNetGetUniversalNameW', 2185952081: 'CreateProcessWithLogonW', 429295890: 'GetUserNameW'}
Đổi tên biến
xx={3196191668: 'LoadLibraryA', 587706791: 'VirtualAlloc', 430125299: 'VirtualFree', 745928694: 'FindFirstFileW', 3310323133: 'FindNextFileW', 2538134804: 'FindClose', 2160950796: 'CreateFileA', 3321973177: 'CreateFileW', 2119526180: 'ReadFile', 2016564646: 'WriteFile', 819148513: 'SetFilePointer', 2706107229: 'WaitForMultipleObjects', 2274961481: 'WaitForSingleObject', 4009797727: 'CreateThread', 2329007555: 'GetFileAttributesW', 1515022974: 'GetFileAttributesA', 4070557793: 'GetModuleFileNameA', 3184347727: 'GetCurrentProcess', 3230171373: 'CloseHandle',1150531511: 'GetWindowsDirectoryA', 2458654477: 'Sleep', 1274182115: 'GetFileSizeEx', 2607238143: 'GetDriveTypeW', 1002302808: 'SetFilePointerEx', 2229935675: 'SetFileAttributesW', 3774275279: 'HeapFree', 2276756918: 'GetProcessHeap', 3884594833: 'GetLogicalDriveStringsW', 2318578073: 'GetDiskFreeSpaceExW', 1560409820: 'FindFirstVolumeW', 3301358813: 'GetVolumePathNamesForVolumeNameW', 922136913:'FindNextVolumeW', 2092703519: 'FindVolumeClose', 2554527287: 'SetVolumeMountPointW', 2432991358: 'GetTempPathW', 3496982552: 'MoveFileW', 373201559: 'VirtualProtect', 1243518349: 'K32EnumProcessModules', 4110329759: 'K32EnumProcessModulesEx', 3017027465: 'K32GetModuleFileNameExA', 65123382: 'GetCommandLineW', 1513489892: 'CreateDirectoryW', 1081677820: 'GetTickCount', 711108549: 'GetModuleFileNameW', 2797954528: 'GetFileSize', 199922510: 'GetWindowsDirectoryW', 1914963876: 'CopyFileW', 1145734755: 'RtlInitializeCriticalSection', 1493453468: 'RtlDeleteCriticalSection', 791102906: 'RtlEnterCriticalSection', 3656038948: 'RtlLeaveCriticalSection', 1967849689: 'RtlAllocateHeap', 57836566: 'BCryptOpenAlgorithmProvider', 1700271275: 'BCryptCloseAlgorithmProvider', 2941172387: 'BCryptGenerateSymmetricKey', 1965304112: 'BCryptSetProperty', 3919218989: 'BCryptGenRandom', 470098108: 'BCryptDestroyKey', 333447649: 'BCryptEncrypt', 1590973787: 'BCryptExportKey', 1777329460: 'BCryptImportKeyPair', 2419093438: 'NetShareEnum', 2261379902:'NetApiBufferFree', 1660342600: 'IcmpCreateFile', 1434042011: 'IcmpCloseHandle', 2363481290: 'GetAdaptersInfo', 2480380205: 'IcmpSendEcho2', 804062357: 'InetNtopW', 2152398498: 'inet_ntop', 2541341025: 'WSAStartup', 1101559834: 'WSACleanup', 689679891: 'inet_addr', 1248996702: 'socket', 2088540052: 'htons', 1497197006: 'connect', 335155875: 'closesocket', 969247798: 'CommandLineToArgvW', 3560560371: 'WNetAddConnection2W', 851486428: 'WNetGetUniversalNameW', 2185952081: 'CreateProcessWithLogonW', 429295890: 'GetUserNameW'}
dword_val=[4380404, 4380328, 4380320, 4380312, 4380244, 4380316, 4380380, 4380184, 4380392, 4380240, 4380188, 4380188, 4380256, 4380340, 4380260, 4380204, 4380204, 4380292, 4380232, 4380352, 4380416, 4380360, 4380296, 4380172, 4380248, 4380288, 4380268, 4380280, 4380280, 4380180, 4380284, 4380208, 4380364, 4380384, 4380252, 4380152, 4380160, 4380192, 4380336, 4380336, 4380356, 4380216, 4380412, 4380144, 4380144, 4380144, 4380144, 4380144, 4380156, 4380168, 4380220, 4380344, 4380276, 4380332, 4380264, 4380140, 4380196, 4380212, 4380164, 4380176, 4380348, 4380300, 4380272, 4380372, 4380400, 4380376, 4380148, 4380200, 4380304, 4380420, 4380224, 4380228, 4380388, 4380324, 4380396, 4380408, 4380236, 4380308, 4380368]
xx1=[]
import idc
for i in xx:
xx1.append(xx[i])
for i in range(len(dword_val)):
idc.set_name(dword_val[i], xx1[i], idaapi.SN_FORCE)
- Kết quả:
5. Argument options
-mc: chạy bình thường
-d <drive_path>: encrypt drive
-ip <shared_network> <user> <pass> :encrypt network
-p <path>: encrypt folder
6. Encryption
- Sử dụng
BCryptOpenAlgorithmProvider
để tạo mộtCNG provider
:
- Tạo file
README.txt
ơ thư mục drive và lưu cái chuỗi trên vào file:
- Dùng
FindFirstFileW
và.
,..
để duyệt tìm các file trong thư mục hiện hành và thư mục cha:
- Né không encrypt loại file
README.txt
và các extensions:.PLAY, .exe, .dll, .lnk, .sys, bootmgr, .msi
- Chương trình tạo 1 cái
thread
riêng để thực hiện encryption:
Data Encryption
- Tạo một
IV
random gồm 16 bytes, sau đó exportAES key
vào một blob có kích thước0x230
bytes:
- Chương trình đọc data từ file rồi tiến hành encrypt data dùng AES key và IV đã tạo sau đó lưu kết quả vào file lại:
Encrypt dựa trên kích thước file
- Nếu kích thước file
>0x500000
bytes: encryptchunk đầu
vàchunk cuối
mỗi chunk0x100000
bytes - Nếu kích thước
<= 0x100000
bytes: encrypt toàn bộ data của file - Nếu kích thước
>0x100000 và <=0x500000
bytes: thực hiện vòng lặp encrypt mỗi lần0x100000
bytes đến chừng nào hết data
Đổi extension
- Sau khi encrypt file, chương trình đổi extension của file thành
.PLAY
: