实际上,这块可以写成汇编,然后做远程注入用
方法
1、通过fs:[30h]获取当前进程的_PEB结构
2、通过_PEB的Ldr成员获取_PEB_LDR_DATA结构
3、通过_PEB_LDR_DATA的InMemoryOrderModuleList成员获取_LIST_ENTRY结构
4、通过_LIST_ENTRY的Flink成员获取_LDR_DATA_TABLE_ENTRY结构,注意:这里的Flink指向的是_LDR_DATA_TABLE_ENTRY结构中的InMemoryOrderLinks成员,因此需要计算真正的_LDR_DATA_TABLE_ENTRY起始地址,我们可以用CONTAINING_RECORD来计算。
5、输出_LDR_DATA_TABLE_ENTRY的BaseDllName或FullDllName成员信息。
1 #include <windows.h> 2 3 #define CONTAINING_RECORD(address, type, field) ((type *)( (PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) 4 5 typedef struct _UNICODE_STRING { 6 USHORT Length; 7 USHORT MaximumLength; 8 PWSTR Buffer; 9 } UNICODE_STRING, *PUNICODE_STRING; 10 11 typedef struct _PEB_LDR_DATA 12 { 13 DWORD Length; 14 UCHAR Initialized; 15 PVOID SsHandle; 16 LIST_ENTRY InLoadOrderModuleList; 17 LIST_ENTRY InMemoryOrderModuleList; 18 LIST_ENTRY InInitializationOrderModuleList; 19 PVOID EntryInProgress; 20 }PEB_LDR_DATA,*PPEB_LDR_DATA; 21 22 typedef struct _LDR_DATA_TABLE_ENTRY 23 { 24 LIST_ENTRY InLoadOrderLinks; 25 LIST_ENTRY InMemoryOrderLinks; 26 LIST_ENTRY InInitializationOrderLinks; 27 PVOID DllBase; 28 PVOID EntryPoint; 29 DWORD SizeOfImage; 30 UNICODE_STRING FullDllName; 31 UNICODE_STRING BaseDllName; 32 DWORD Flags; 33 WORD LoadCount; 34 WORD TlsIndex; 35 LIST_ENTRY HashLinks; 36 PVOID SectionPointer; 37 DWORD CheckSum; 38 DWORD TimeDateStamp; 39 PVOID LoadedImports; 40 PVOID EntryPointActivationContext; 41 PVOID PatchInformation; 42 }LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY; 43 44 typedef struct _PEB 45 { 46 UCHAR InheritedAddressSpace; 47 UCHAR ReadImageFileExecOptions; 48 UCHAR BeingDebugged; 49 UCHAR SpareBool; 50 PVOID Mutant; 51 PVOID ImageBaseAddress; 52 PPEB_LDR_DATA Ldr; 53 }PEB,*PPEB; 54 55 int main(void) 56 { 57 PLDR_DATA_TABLE_ENTRY pLdrDataEntry = NULL; 58 PLIST_ENTRY pListEntryStart = NULL,pListEntryEnd = NULL; 59 PPEB_LDR_DATA pPebLdrData = NULL; 60 PPEB pPeb = NULL; 61 62 __asm 63 { 64 //1、通过fs:[30h]获取当前进程的_PEB结构 65 mov eax,dword ptr fs:[30h]; 66 mov pPeb,eax 67 } 68 69 //2、通过_PEB的Ldr成员获取_PEB_LDR_DATA结构 70 pPebLdrData = pPeb->Ldr; 71 72 //3、通过_PEB_LDR_DATA的InMemoryOrderModuleList成员获取_LIST_ENTRY结构 73 pListEntryStart = pListEntryEnd = pPebLdrData->InMemoryOrderModuleList.Flink; 74 75 //查找所有已载入到内存中的模块 76 do 77 { 78 //4、通过_LIST_ENTRY的Flink成员获取_LDR_DATA_TABLE_ENTRY结构 79 pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(pListEntryStart,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks); 80 81 //5、输出_LDR_DATA_TABLE_ENTRY的BaseDllName或FullDllName成员信息 82 printf("%S ",pLdrDataEntry->BaseDllName.Buffer); 83 84 pListEntryStart = pListEntryStart->Flink; 85 86 }while(pListEntryStart != pListEntryEnd); 87 88 89 return 0; 90 }
注入相关的代码在这里
1 #include <Windows.h> 2 3 #include <stdio.h> 4 5 typedef struct _UNICODE_STRING { 6 USHORT Length; 7 USHORT MaximumLength; 8 PWCH Buffer; 9 } UNICODE_STRING; 10 11 typedef struct _LDR_DATA_TABLE_ENTRY 12 { 13 LIST_ENTRY InLoadOrderLinks; 14 LIST_ENTRY InMemoryOrderLinks; 15 LIST_ENTRY InInitializationOrderLinks; 16 PVOID DllBase; 17 PVOID EntryPoint; 18 ULONG SizeOfImage; 19 UNICODE_STRING FullDllName; 20 UNICODE_STRING BaseDllName; 21 ULONG Flags; 22 WORD LoadCount; 23 WORD TlsIndex; 24 union 25 { 26 LIST_ENTRY HashLinks; 27 struct 28 { 29 PVOID SectionPointer; 30 ULONG CheckSum; 31 }; 32 }; 33 union 34 { 35 ULONG TimeDateStamp; 36 PVOID LoadedImports; 37 }; 38 void * EntryPointActivationContext; 39 PVOID PatchInformation; 40 LIST_ENTRY ForwarderLinks; 41 LIST_ENTRY ServiceTagLinks; 42 LIST_ENTRY StaticLinks; 43 } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 44 45 // 把一个字符串做成一个 hash 值 46 __declspec(naked) DWORD __stdcall HashString( WCHAR *name ) 47 { 48 __asm 49 { 50 push esi; 51 push edi; 52 mov esi , [esp + 0x0C]; 53 xor edi , edi; 54 cld; 55 __iter: 56 xor eax , eax; 57 lodsw ; 58 cmp al , ah; 59 je __done; 60 ror edi , 0x0D; 61 add edi ,eax ; 62 jmp __iter; 63 __done: 64 mov eax , edi; 65 pop edi; 66 pop esi; 67 retn 4; 68 } 69 } 70 71 // 遍历 LDR 表,找到要找的 DLL 基址 72 PVOID __stdcall GetDllBase( LIST_ENTRY *head , DWORD hash ) 73 { 74 PLDR_DATA_TABLE_ENTRY t; 75 LIST_ENTRY *p = head->Flink; 76 for ( ; p != head ; p = p->Flink ) 77 { 78 t = (PLDR_DATA_TABLE_ENTRY)((char*)p - 0x10); 79 if ( hash == HashString( t->BaseDllName.Buffer ) ) 80 { 81 return t->DllBase; 82 } 83 } 84 return 0; 85 } 86 87 // 从 fs 段找到 TEB ,从 TEB 找到 PEB ,从 PEB 找到 LDR 表 88 // 返回值为 LDR 表链的头节点 89 __declspec(naked) LIST_ENTRY * __stdcall FindLDRTable() 90 { 91 __asm 92 { 93 push esi; 94 xor eax , eax; 95 mov eax , fs:[0x30]; 96 test eax , eax; 97 js __k9x; 98 mov eax , [eax + 0x0C]; 99 lea esi , [eax + 0x1C]; 100 mov eax , esi; 101 jmp near __finish; 102 __k9x: 103 xor eax , eax; 104 __finish: 105 pop esi; 106 ret; 107 } 108 } 109 110 // 获取一个已经加载了的模块地址 111 // name 只是名字,不可以是路径带名字 112 PVOID LoadLibraryIn( WCHAR *name ) 113 { 114 return GetDllBase( FindLDRTable() , HashString( name ) ); 115 } 116 117 int main() 118 { 119 //printf("0x%p " , HashString(L"kernel32.dll")); 120 //printf("0x%p " , HashString(L"User32.dll")); 121 122 printf( "0x%p " , LoadLibraryIn( L"kernel32.dll" ) ); 123 printf( "0x%p " , LoadLibraryA( "kernel32.dll" ) ); 124 printf( "0x%p " , LoadLibraryA( "ntdll.dll" ) ); 125 126 return 0; 127 }
用汇编来做3个关键函数,然后shellcode获取模块基址,计算PE,得到导出表,根据名称表找到对应的名字,地址表直接就能找到对应的函数地址了,
比较类似,自重定位,然后LoadLibrary GetProcAddress 了