本文为看雪论坛精华文章
看雪论坛作者ID:renzhexigua
# 查看当前加载模块
> lm
# 查看内存模块布局
> !address
# 将指定范围的内存数据保存至本地文件
> .writemem /path/to/dumpfile.dmp StartAddress Range
# 查看相关符号
> ln address
0:000> lmDvm112_http_stager
Browse full module list
start end module name
00400000 00409000 112_http_stager (no symbols)
Loaded symbol image file: 112_http_stager.exe
Image path: X:\unpack\112_http_stager.exe
Image name: 112_http_stager.exe
Browse all global symbols functions data
Timestamp: Tue Jun 9 08:17:15 2020 (5EDED50B)
CheckSum: 00010C4A
ImageSize: 00009000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
Information from resource tables:
.writemem /path/to/dump.dmp 00400000 L9000
Small tool to convert beteween the PE alignments (raw and virtual). Allows for easy PE unmapping: useful in recovering executables dumped from the memory.
pe_unmapper.exe /in dump.mem 00400000 /out 112_http_stager.exe
2022-09-13 10:40 PM 14,336 112_http_stager.exe <== 展开前/修复后的文件 1
2022-09-13 05:38 PM 52,110,299 112_http_stager.exe.dmp
2022-09-13 06:02 PM 36,864 dump.mem <== 展开后/修复前从 dmp 中提取的文件
pe_unmapper.exe /in dump.mem 00400000 /out 112_http_stager_mode_r.exe /mode r
2022-09-13 10:40 PM 14,336 112_http_stager.exe <== 修复后的文件 1
2022-09-13 05:38 PM 52,110,299 112_http_stager.exe.dmp
2022-09-13 10:54 PM 36,864 112_http_stager_mode_r.exe <== 修复后的文件 2
2022-09-13 06:02 PM 36,864 dump.mem <== 展开后/修复前从 dmp 中提取的文件
使用 pe_unmapper.exe /in NotePad.virtual.pe 0x400000 /out NotePad.realign.exe /mode r 得到 section realign 后的 PE 文件
借助:IDAPython + dumpulator + lief
import idc
import ida_xref
import idautils
import ida_bytes
# .idata segment
segm_start = 0x406000
segm_end = 0x407000
dInfos = dict()
for ea in range(segm_start, segm_end, 4):
val = ida_bytes.get_dword(ea)
for ref in idautils.XrefsTo(ea, ida_xref.XREF_DATA):
if ref.type in [idc.dr_R]:
entry = dInfos.setdefault(ea, {'val': val, 'refs': set()})
entry['refs'].add(ref.frm)
lInfos = []
for k, v in dInfos.items():
lInfos.append((k, v['val']))
print(dInfos)
{
IAT1_VA: {
'val': export_func_addr,
'refs': set(call_insn_addrs),
'name': export_func_name
},
IAT2_VA: {
...snip...
},
...snip...
}
{
4219616: {'refs': {4203561, 4203598}, 'val': 1993408960},
4219620: {'refs': {4203732, 4203654}, 'val': 1993402960}
...snip...
}
Dumpulator:是一个用以对 minidump 文件进行模拟执行的 Python 库
from dumpulator import Dumpulator
dp = Dumpulator('NotePad.exe.dmp', quiet=True)
lInfos = [(4219616, 1993408960), (4219620, 1993402960), ...snip...]
lInfoWithSymbols1 = []
for entry in lInfos:
iat_addr, func_addr = entry
try:
name = dp.exports[func_addr]
lInfoWithSymbols1.append((iat_addr, func_addr, name))
except:
# unfixed issue: https://github.com/mrexodia/dumpulator/issues/3
print(f'{iat_addr},{func_addr}, cannot parse address')
continue
print(lInfoWithSymbols)
iat_address, func_address, func_name
[(4219616, 1993408960, 'advapi32.dll:RegSetValueExA'),
...snip...
(4219628, 1993408992, 'advapi32.dll:RegOpenKeyA'),
(4219640, 1993104976, 'gdi32.dll:GetStockObject'),
(4219644, 1993096672, 'gdi32.dll:GetObjectA'),
(4219820, 2004124400, 'ntdll.dll:RtlMoveMemory'),
...snip...
(4219904, 1978456096, 'shell32.dll:DragQueryFileA'),
(4219908, 1978456080, 'shell32.dll:DragFinish'),
...snip...
(4220040, 1984116832, 'user32.dll:CharNextA'),
(4220044, 1984147904, 'user32.dll:IsDialogMessageA'),
...snip...
(4219816, 1994756464, 'kernel32.dll:GetProfileStringA'),
...snip...
(4219872, 1994792672, 'kernel32.dll:GetCommandLineA')]
# 方法 1
import lief
# PE
input_path = "NotePad.demo.exe"
artifact_path = "NotePad.demo.fixed.exe"
binary = lief.parse(input_path)
dInfos = {
4219616: {'refs': {4203561, 4203598}, 'val': 1993408960, 'name': 'advapi32.dll:RegSetValueExA'},
4219620: {'refs': {4203732, 4203654}, 'val': 1993402960, 'name': 'advapi32.dll:RegQueryValueExA'},
4219624: {'refs': {4204169}, 'val': 1993403168, 'name': 'advapi32.dll:RegCloseKey'},
...snip...
}
# Rebuild IAT entries
for info in dInfos.values():
symbol_name = info['name']
lib_name, entry_name = symbol_name.split(':')
lib = binary.get_import(lib_name)
# create new library if not exist
if not lib:
lib = binary.add_library(lib_name)
entry = lib.get_entry(entry_name)
# add new function entry if not exist
if not entry:
entry = lib.add_entry(entry_name)
# Fix IAT-related call reference
imagebase = binary.optional_header.imagebase
for info in dInfos.values():
symbol_name = info['name']
lib_name, entry_name = symbol_name.split(':')
# iat_addr_va: LIEF reassigned address
iat_addr_va = imagebase + binary.predict_function_rva(lib_name, entry_name)
for insn_va in info['refs']:
# print(f'{lib_name}!{entry_name} called by 0x{insn_va:x}: (insn) call 0x{iat_addr_va:x}')
# Actually, the mnemonics of insn calling IAT include: CALL, JMP, etc.
# Ref: https://github.com/volatilityfoundation/volatility/blob/master/volatility/plugins/malware/impscan.py#L197-L219
#
# FF 15 dd cc bb aa CALL 0xaabbccdd
binary.patch_address(insn_va + 2, iat_addr_va, 4, binary.VA_TYPES.VA)
# Modify the EP
binary.optional_header.addressof_entrypoint = 0x10CC
# Apply these changes
builder = lief.PE.Builder(binary)
builder.build_imports(True)
builder.patch_imports(True)
builder.build()
# Save this artifact
builder.write(artifact_path)
借助:ApiScout + lief
apiscout\db_builder> python DatabaseBuilder.py --auto
{
"aslr_offsets": true,
"crawled_paths": [
"C:\\Windows\\system32",
"C:\\Windows\\SysWOW64",
"C:\\Windows\\WinSxS",
"C:\\Program Files\\Common Files"
],
"dlls": {
"32_0.0.0.0_ActionCenter.dll_0x10000000": {
"aslr_offset": -1264844800,
"base_address": 268435456,
"bitness": 32,
"exports": [
{
"address": 73712,
"name": "DllCanUnloadNow",
"ordinal": 1
},
{
"address": 98864,
"name": "DllGetClassObject",
"ordinal": 2
}
],
"filepath": "C:\\Windows\\SysWOW64\\ActionCenter.dll",
"version": "0.0.0.0"
},
"32_0.0.0.0_AudioSes.dll_0x10000000": {
"aslr_offset": -1283457024,
"base_address": 268435456,
"bitness": 32,
"exports": [
{
"address": 200912,
"name": "DllGetClassObject",
"ordinal": 9
},
...snip...
}
}
python scout.py \"X:\NotePad.demo.exe\" 10.0_filtered.json
idx: offset ; VA ; IT?; #ref;DLL ; API
1: 0x000062e0; 0x76d101c0; err; 3; advapi32.dll_0x4c300000 (32bit) ; RegSetValueExA
2: 0x000062e4; 0x76d0ea50; err; 3; advapi32.dll_0x4c300000 (32bit) ; RegQueryValueExA
3: 0x000062e8; 0x76d0eb20; err; 2; advapi32.dll_0x4c300000 (32bit) ; RegCloseKey
4: 0x000062ec; 0x76d101e0; err; 2; advapi32.dll_0x4c300000 (32bit) ; RegOpenKeyA
5: 0x000062f0; 0x76d13190; err; 2; advapi32.dll_0x4c300000 (32bit) ; RegCreateKeyA
6: 0x000062f8; 0x76cc5e50; err; 2; gdi32.dll_0x4d500000 (32bit) ; GetStockObject
...snip...
155: 0x0000e35d; 0x72005000; err; 1; rasman.dll_0x10000000 (32bit) ; RasSignalMonitorThreadExit
---------------------------------------------------------------------------------------------------------------------------------
156: 0x0000e3d1; 0x72005000; err; 1; rasman.dll_0x10000000 (32bit) ; RasSignalMonitorThreadExit
DLLs: 8, APIs: 145, references: 389
WinApi1024 Vector Results:
Windows 10 (AMD64): 63 / 145 (43.45%) APIs covered in WinApi1024 vector.
Vector: A67EAAIAQA5BA8CAQEA8CAAQAAQACA5EAHA+A4HAMA3QAABAwA3IgCggIEAAEDABgEGKIOKgA3CIgEiJgEBg
Confidence: 89.97354108424373
idx: offset ; VA ; IT?; #ref;DLL ; API
1: 0x004062e0; 0x76d101c0; err; 3; advapi32.dll_0x4c300000 (32bit) ; RegSetValueExA
2: 0x004062e4; 0x76d0ea50; err; 3; advapi32.dll_0x4c300000 (32bit) ; RegQueryValueExA
3: 0x004062e8; 0x76d0eb20; err; 2; advapi32.dll_0x4c300000 (32bit) ; RegCloseKey
4: 0x004062ec; 0x76d101e0; err; 2; advapi32.dll_0x4c300000 (32bit) ; RegOpenKeyA
python scout.py \"X:\NotePad.demo.exe\" 10.0_filtered.json -o NotePad.demo.apis.json
[
{
"offset": 25312,
"apiAddress": 1993408960,
"dll": "advapi32.dll(32 bit)",
"api": "RegSetValueExA",
"references": [
9257,
9294
]
},
{
"offset": 25444,
"apiAddress": 1995044640,
"dll": "kernel32.dll(32 bit)",
"api": "_lwrite",
"references": [
13005,
13092
]
},
{
"offset": 25448,
"apiAddress": 1994786592,
"dll": "kernel32.dll(32 bit)",
"api": "LocalUnlock",
"references": [
13022,
13174,
13699,
13794,
13906,
14657,
15018,
15062,
15083,
16643,
17155
]
},
...snip...
{
"offset": 57483,
"apiAddress": 1991430304,
"dll": "comdlg32.dll(32 bit)",
"api": "GetOpenFileNameA",
"references": []
},
{
"offset": 57491,
"apiAddress": 1993408960,
"dll": "advapi32.dll(32 bit)",
"api": "RegSetValueExA",
"references": []
},
{
"offset": 58205,
"apiAddress": 1912623104,
"dll": "rasman.dll(32 bit)",
"api": "RasSignalMonitorThreadExit",
"references": []
},
{
"offset": 58321,
"apiAddress": 1912623104,
"dll": "rasman.dll(32 bit)",
"api": "RasSignalMonitorThreadExit",
"references": []
}
]
该 json 输出中把我们在方法 1 中结合使用 IDAPython + dumpulator 所建立的映射关系直接呈现了出来。同时还把之前提到的实际未被引用的 API 也给标记了出来,如上图中 references 表示实际被应用的位置(即,call/jmp [iat_address] 指令的起始位置),可以看到,RasSignalMonitorThreadExit 等函数实际并未使用,references 列表为空。
# 方法 2
import json
import lief
# PE
input_path = "NotePad.demo.exe"
artifact_path = "NotePad.demo.fixed.exe"
binary = lief.parse(input_path)
api_path = "api.json"
dInfos = None
with open(api_path, 'r') as f:
dInfos = json.load(f)
# Rebuild IAT entries
for info in dInfos:
...snip...
# 方法 1
import lief
# PE
input_path = "NotePad.demo.exe"
artifact_path = "NotePad.demo.fixed.exe"
binary = lief.parse(input_path)
dInfos = {
4219616: {'refs': {4203561, 4203598}, 'val': 1993408960, 'name': 'advapi32.dll:RegSetValueExA'},
4219620: {'refs': {4203732, 4203654}, 'val': 1993402960, 'name': 'advapi32.dll:RegQueryValueExA'},
4219624: {'refs': {4204169}, 'val': 1993403168, 'name': 'advapi32.dll:RegCloseKey'},
4219628: {'refs': {4204221}, 'val': 1993408992, 'name': 'advapi32.dll:RegOpenKeyA'},
...snip...
}
# Rebuild IAT entries
for info in dInfos:
...snip...
看雪ID:renzhexigua
https://bbs.pediy.com/user-home-752377.htm
2.5折门票限时抢购
峰会官网:https://meet.kanxue.com/kxmeet-6.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!