分析这个函数最初是因为 代码注入远程进程时 需要确定远程进程的模块基址
RING3下 通过调用EnumProcessModules来实现 仔细分析了下 实际上不需要调用函数
通过PEB结构直接就可以知道IMAGEBASE
.text:687E1981 ; BOOL __stdcall EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded)
.text:687E1981 public _EnumProcessModules@16
.text:687E1981 _EnumProcessModules@16 proc near
.text:687E1981
.text:687E1981 var_9C = dword ptr -9Ch
.text:687E1981 var_94 = byte ptr -94h
.text:687E1981 var_8C = dword ptr -8Ch
.text:687E1981 var_7C = dword ptr -7Ch
.text:687E1981 var_4C = dword ptr -4Ch
.text:687E1981 Buffer = dword ptr -48h
.text:687E1981 var_40 = byte ptr -40h
.text:687E1981 var_3C = dword ptr -3Ch
.text:687E1981 var_24 = dword ptr -24h
.text:687E1981 var_18 = dword ptr -18h
.text:687E1981 var_14 = dword ptr -14h
.text:687E1981 var_10 = dword ptr -10h
.text:687E1981 var_4 = dword ptr -4
.text:687E1981 hProcess = dword ptr 8
.text:687E1981 lphModule = dword ptr 0Ch
.text:687E1981 cb = dword ptr 10h
.text:687E1981 lpcbNeeded = dword ptr 14h
.text:687E1981
.text:687E1981 push ebp
.text:687E1982 mov ebp, esp
.text:687E1984 push 0FFFFFFFFh
.text:687E1986 push offset dword_687E1330
.text:687E198B push offset __except_handler3
.text:687E1990 mov eax, large fs:0
.text:687E1996 push eax
.text:687E1997 mov large fs:0, esp ; 异常处理
.text:687E199E push ecx
.text:687E199F push ecx
.text:687E19A0 sub esp, 88h
.text:687E19A6 push ebx
.text:687E19A7 push esi
.text:687E19A8 push edi
.text:687E19A9 mov [ebp+var_18], esp
.text:687E19AC xor ebx, ebx
.text:687E19AE push ebx ; &ReturnLength
.text:687E19AF push 18h ; sizeof(PROCESS_BASIC_INFORMATION)
.text:687E19B1 lea eax, [ebp+var_40]
.text:687E19B4 push eax ; &PROCESS_BASIC_INFORMATION
.text:687E19B5 push ebx ; ProcessBasicInformation (0)
.text:687E19B6 push [ebp+hProcess] ; hProcess
.text:687E19B9 call ds:__imp__NtQueryInformationProcess@20 ; NtQueryInformationProcess(x,x,x,x,x)
.text:687E19BF cmp eax, ebx ; PROCESS_BASIC_INFORMATION
.text:687E19C1 jge short loc_687E19D8 ; ntStatus == STATUS_SUCCESS
.text:687E19C3 push eax
.text:687E19C4 call ds:__imp__RtlNtStatusToDosError@4 ; RtlNtStatusToDosError(x)
.text:687E19CA push eax ; dwErrCode
.text:687E19CB call ds:__imp__SetLastError@4 ; SetLastError(x)
.text:687E19D1
.text:687E19D1 loc_687E19D1: ; CODE XREF: EnumProcessModules(x,x,x,x)+72j
.text:687E19D1 ; EnumProcessModules(x,x,x,x)+8Cj ...
.text:687E19D1 xor eax, eax
.text:687E19D3 jmp loc_687E1A9A
.text:687E19D8 ; ---------------------------------------------------------------------------
.text:687E19D8
.text:687E19D8 loc_687E19D8: ; CODE XREF: EnumProcessModules(x,x,x,x)+40j
.text:687E19D8 push ebx ; lpNumberOfBytesRead
.text:687E19D9 push 4 ; nSize
.text:687E19DB lea eax, [ebp+Buffer]
.text:687E19DE push eax ; lpBuffer
.text:687E19DF mov eax, [ebp+var_3C] ; PROCESS_BASIC_INFORMATION.PPEB
.text:687E19E2 add eax, 0Ch ; &PPEB->Ldr
.text:687E19E5 push eax
.text:687E19E6 push [ebp+hProcess] ; hProcess
.text:687E19E9 mov edi, ds:__imp__ReadProcessMemory@20 ; ReadProcessMemory(x,x,x,x,x)
.text:687E19EF call edi ; ReadProcessMemory(x,x,x,x,x) ; ReadProcessMemory(x,x,x,x,x)
.text:687E19F1 test eax, eax ; 读取到Ptr32 _PEB_LDR_DATA
.text:687E19F3 jz short loc_687E19D1
.text:687E19F5 mov eax, [ebp+Buffer] ; ebp+buffer 存放的是_PEB_LDR_DATA结构的地址
.text:687E19F8 add eax, 14h ; &_PEB_LDR_DATA.InMemoryOrderModuleList
.text:687E19FB mov [ebp+var_4C], eax
.text:687E19FE push ebx ; lpNumberOfBytesRead
.text:687E19FF push 4 ; nSize
.text:687E1A01 lea ecx, [ebp+var_24]
.text:687E1A04 push ecx ; lpBuffer
.text:687E1A05 push eax ; &_PEB_LDR_DATA.InMemoryOrderModuleList
.text:687E1A06 push [ebp+hProcess] ; hProcess
.text:687E1A09 call edi ; ReadProcessMemory(x,x,x,x,x) ; ReadProcessMemory(x,x,x,x,x)
.text:687E1A0B test eax, eax ; 读取到 _PEB_LDR_DATA.InMemoryOrderModuleList
.text:687E1A0D jz short loc_687E19D1
.text:687E1A0F mov esi, [ebp+cb] ; size in bytes
.text:687E1A12 shr esi, 2 ; size in dwords
.text:687E1A15 mov eax, [ebp+var_24] ; InMemoryOrderModuleList.flink(flink指向下一个的_PEB_LDR_DATA的ListEntry段)
.text:687E1A18
.text:687E1A18 loc_687E1A18: ; CODE XREF: EnumProcessModules(x,x,x,x)+D3j
.text:687E1A18 cmp eax, [ebp+var_4C] ; 链表遍历结束
.text:687E1A1B jz short loc_687E1A86
.text:687E1A1D push 0 ; lpNumberOfBytesRead
.text:687E1A1F push 48h ; nSize
.text:687E1A21 lea ecx, [ebp+var_94]
.text:687E1A27 push ecx ; lpBuffer
.text:687E1A28 add eax, 0FFFFFFF8h
.text:687E1A2B push eax ; lpBaseAddress
.text:687E1A2C push [ebp+hProcess] ; hProcess
.text:687E1A2F call edi ; ReadProcessMemory(x,x,x,x,x) ; ReadProcessMemory(x,x,x,x,x)
.text:687E1A31 test eax, eax ; 读取 InLoadOrderModuleList.flink开始的48H个字节
.text:687E1A33 jz short loc_687E19D1
.text:687E1A35 cmp ebx, esi
.text:687E1A37 jnb short loc_687E1A4A
.text:687E1A39 and [ebp+var_4], 0
.text:687E1A3D mov eax, [ebp+var_7C]; _PEB_LDR_DATA.EntryInProgress
.text:687E1A40 mov ecx, [ebp+lphModule]
.text:687E1A43 mov [ecx+ebx*4], eax
.text:687E1A46 or [ebp+var_4], 0FFFFFFFFh
.text:687E1A4A
.text:687E1A4A loc_687E1A4A: ; CODE XREF: EnumProcessModules(x,x,x,x)+B6j
.text:687E1A4A inc ebx
.text:687E1A4B mov eax, [ebp+var_8C];InMemoryOrderModuleList.flink
.text:687E1A51 mov [ebp+var_24], eax
.text:687E1A54 jmp short loc_687E1A18 ; 链表遍历结束
上面可以看出函数得到进程中各模块的基址 是通过InMemoryOrderModuleList.Flink来遍历的
我们知道EnumProcessModules函数得到的hModule数组中hModule[0]中存放的就是进程基址,而
从上面的反汇编可以看出 hModule[0]里存放的是_PEB_LDR_DATA[1]中的EntryInProgress
_PEB_LDR_DATA[0]中的是EntryInProgress为0,_PEB_LDR_DATA[0]很明显作为双链表的表头来使用
_PEB_LDR_DATA.InMemoryOrderModuleList故名思义 它指向的双链表 是按照在内存中虚拟地址的大小的排列顺序链接的
_PEB_LDR_DATA.InInitializationOrderModuleList 指向的双链表 链接的是初始化时的_PEB_LDR_DATA结构
_PEB_LDR_DATA.InLoadOrderModuleList 它所指向的双链表 是按照载入内存的先后顺序来排列的 ring3其中一个
隐藏模块技术就是 断掉InMemoryOrderModuleList指向的双链表
远程线程中得到进程模块基址 只需要插几句汇编就行
mov eax,fs:[30h] ;Ptr32 _PEB
mov ebx,[eax+8h] ;进程的基址
或者
mov eax,fs:[30h] ;Ptr32 _PEB
mov eax,[eax+0ch] ;Ptr32 _PEB_LDR_DATA
mov eax,[eax+14h] ;_PEB_LDR_DATA[1]
mov edx,[eax+10h] ;edx存放的就是进程基址
注:后来查了下网上的资料 _PEB_LDR_DATA的3条链表 实际指向的是_LDR_MODULE结构 但是XP下_PEB_LDR_DATA结构增加了entryinprocess字段 所以只取基址的话 无影响
只取基址的
579

被折叠的 条评论
为什么被折叠?



