一般的可执行恶意样本的INT(导入名称表)在一定程度上就暴露了自己的行为,所以又来保护自己了。下面是一个样本中的实际应用,从PE文件结构入手。为了可以调用相关的API (由kernel32.dll ,ntdll.dll等导出,它先找到目标dll在内存中加载的地址(这些系统dll已经有系统加载到内存中),然后就是根据PE文件结构一顿操作,主要是通过导出名称字符生成一个DWORD数去比对,在找到FuncAddr。下面是相关操作的反汇编代码:
GetModuleAddr proc near
push ebp
mov ebp,esp
mov eax,large fs:30h ;fs 寄存器指向当前线程环境块,是内核的结构,可以通过WinDbg去详细查看。在偏移为30h 的地方是Teb->ProcessEnvironmentBlock 进程环境块
mov eax,[eax+0ch] ; Peb->Ldr
mov eax,[eax+1ch];Ldr->InitializationOrderModuleList
mov eax,[eax+8] ;由于系统的版本不一样,同一个dll加载的顺序可能不一样
pop ebp
retn
GetModuleAddr endp
;通过名称在ENT中找到该函数的导出序号,再去EAT得到地址就可以调用了
GetFuncAddr proc near
var_24 = dword ptr -24h
var_20 = dword ptr -20h
var_1C = dword ptr -1Ch
var_18 = dword ptr -18h
var_14 = dword ptr -14h
var_10 = dword ptr -10h ;该函数用的变量
var_C = dword ptr -0Ch
var_8 = dword ptr -8
ExportDirectory = dword ptr -4
arg_0 = dword ptr 8
arg_4 = dword ptr 0Ch;3个参数
Addr = dword ptr 10h
;可以对照PE结构文档看
push ebp
mov ebp, esp
sub esp, 24h
mov eax, [ebp+arg_0];模块地址
mov eax, [eax+3Ch] ;3c---ImageDosHeader->e_lfanew PE文件头的偏移
mov ecx, [ebp+arg_0]
lea eax, [ecx+eax+18h];[eax+ecx]是PE文件头的地址,再加上18h 是扩展头的地址
mov [ebp+var_10], eax
mov eax, [ebp+var_10] ; OptionalHeader
mov ecx, [ebp+arg_0]
add ecx, [eax+60h] ;IMAGE_DATA_DIRECTORY
mov [ebp+ExportDirectory], ecx
mov eax, [ebp+arg_4]
shr eax, 10h ;右移10h位
movzx eax, ax ;去低16位
test eax, eax
jnz short loc_402672;是否使用原可执行文件中得到地址
mov eax, [ebp+arg_4]
loc_40265F:
and eax, 0FFFFh
movzx eax, ax
mov ecx, [ebp+ExportDirectory]
sub eax, [ecx+10h] ; Base
mov [ebp+var_C], eax
jmp short loc_4026E9
loc_402672:
mov eax, [ebp+ExportDirectory]
mov ecx, [ebp+arg_0]
add ecx, [eax+20h] ; AddressOfNames
mov [ebp+var_1C], ecx
mov eax, [ebp+ExportDirectory]
mov ecx, [ebp+arg_0]
add ecx, [eax+24h] ; AddressOfNameOrdinals
mov [ebp+var_24], ecx
and [ebp+var_20], 0
jmp short loc_4026A8
loc_402690:
mov eax, [ebp+var_20]
inc eax
mov [ebp+var_20], eax
mov eax, [ebp+var_1C]
add eax, 4
mov [ebp+var_1C], eax
mov eax, [ebp+var_24]
inc eax
inc eax
mov [ebp+var_24], eax
loc_4026A8:
mov eax, [ebp+ExportDirectory]
mov ecx, [ebp+var_20]
cmp ecx, [eax+18h];NumberOfNames
jnb short loc_4026DA ;是否超过了导出名称数
push [ebp+arg_4]
mov eax, [ebp+var_1C]
mov ecx, [ebp+arg_0]
add ecx, [eax]
push ecx
call CompareStr ;匹配成功返回1
pop ecx
pop ecx
movzx eax, al
test eax, eax
jz short loc_4026D8
mov eax, [ebp+var_24]
movzx eax, word ptr [eax]
mov [ebp+var_C], eax;var_c目标序号
jmp short loc_4026DA
loc_4026D8:
jmp short loc_402690 ;匹配失败,往回走
loc_4026DA:
mov eax, [ebp+ExportDirectory]
mov ecx, [ebp+var_20]
cmp ecx, [eax+18h]
jnz short loc_4026E9
xor eax, eax
jmp short locret_402715
loc_4026E9:
mov eax, [ebp+ExportDirectory]
mov ecx, [ebp+arg_0]
add ecx, [eax+1Ch] ; AddressOfFunctions
mov [ebp+var_8], ecx
mov eax, [ebp+var_C]
mov ecx, [ebp+var_8]
mov eax, [ecx+eax*4] ;最后从EAT中取出地址
mov [ebp+var_18], eax
mov eax, [ebp+arg_0]
add eax, [ebp+var_18]
mov [ebp+var_14], eax
mov eax, [ebp+Addr]
mov ecx, [ebp+var_14]
mov [eax], ecx
xor eax, eax
inc eax ; succeed
locret_402715:
leave
retn
GetFuncAddr endp