LoadLibrary下面分别调用了LoadLibraryEx。LoadLibraryEx里面有几个参数哦。。可以把文件调入进来不执行DllMain,或者当做资源文件加载进来。然后通过RtlAnsiStringToUnicodeString将文件名转换为UNICODE String,然后调用下层函数 LoadLibraryExW..(这里学到2个函数wcschr,wcsrchr,wcslen看来ntdll里面也有很多字符串函数)。然后就是根据环境变量看看系统目录(如果当前目录下没有dll,那就到系统目录下windows/system32下去找dll)。
然后在zwOpenFile下断吧。(这里是打开dll文件。) zwopenfile后调用ZwCreateSection函数。顾名思意大概也猜到什么意思了。然后就是调用
ZwMapViewOfSection函数。呵呵。开始装载执行体进内存了。
然后又看到一个不错的函数-RtlImageNtHeader---用起来真方便啊。(LdrEnumerateLoadedModules这个函数也不错哦。在ntdll中),随后用RtlImageDirectoryEntryToData,该函数我查到资料如下:
DWORD RtlImageDirectoryEntryToData(DWORD imagebase,BOOL bVA,DWORD dwDataDirectoryIndex, DWORD *size);
其中,imagebase 为模块基址,也就是MZ开头的地方, bVA为真表示函数返回一个VA, 否则函数返回一个PointerToRawData(减去基址就是在文件中的位置),
dwDataDirectoryIndex为索引值, 从0到f,如0表示导出表。
size为接受这项数据目录大小的指针。
如果该索引不存在, 那么函数返回0, 并且不改变size指针的值。
解释的很清楚了。。呵呵。。(第一次看到这个函数,系统调用查询时COM的DataDirectory。)
随后通过在系统中加载的基地址和dll的入口点,代码如下:
7C93C6D9 8BFF mov edi, edi
7C93C6DB 55 push ebp
7C93C6DC 8BEC mov ebp, esp
7C93C6DE FF75 08 push dword ptr [ebp+8]
7C93C6E1 E8 533CFFFF call RtlImageNtHeader
7C93C6E6 85C0 test eax, eax
7C93C6E8 74 0A je short 7C93C6F4
7C93C6EA 8B40 28 mov eax, dword ptr [eax+28] ; dll的入口点
7C93C6ED 85C0 test eax, eax
7C93C6EF 74 03 je short 7C93C6F4
7C93C6F1 0345 08 add eax, dword ptr [ebp+8] ; [ebp+8]为加载的基地址
7C93C6F4 5D pop ebp
7C93C6F5 C2 0400 retn 4
随后来到重定位表项:
7C93DF15 33DB xor ebx, ebx
7C93DF17 385D C2 cmp byte ptr [ebp-3E], bl
7C93DF1A 0F84 89050000 je 7C93E4A9
7C93DF20 F646 34 04 test byte ptr [esi+34], 4
7C93DF24 0F84 12E90000 je 7C94C83C
7C93DF2A 8B45 A0 mov eax, dword ptr [ebp-60]
7C93DF2D F640 16 01 test byte ptr [eax+16], 1
7C93DF31 75 1B jnz short 7C93DF4E
7C93DF33 895D 84 mov dword ptr [ebp-7C], ebx
7C93DF36 8D45 84 lea eax, dword ptr [ebp-7C]
7C93DF39 50 push eax
7C93DF3A 6A 05 push 5 ; 到了重定位表项了
7C93DF3C 6A 01 push 1
7C93DF3E FF75 E4 push dword ptr [ebp-1C]
7C93DF41 E8 0024FFFF call RtlImageDirectoryEntryToData
7C93DF46 3BC3 cmp eax, ebx
7C93DF48 0F84 E5E80000 je 7C94C833
7C93DF4E C645 C3 01 mov byte ptr [ebp-3D], 1
7C93DF52 B8 5CF8997C mov eax, 7C99F85C
7C93DF57 8945 80 mov dword ptr [ebp-80], eax
然后通过函数
ZwProtectVirtualMemory(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN OUT PULONG NumberOfBytesToProtect,
IN ULONG NewAccessProtection,
OUT PULONG OldAccessProtection );设置各个段的属性。分别可以是读写执行等。
-----------------------------------------------------------------
精彩地方来了,重定位的地方来了。。呵呵。。
7C93E06D 8BFF mov edi, edi
7C93E06F 55 push ebp
7C93E070 8BEC mov ebp, esp
7C93E072 83EC 10 sub esp, 10
7C93E075 53 push ebx
7C93E076 56 push esi
7C93E077 57 push edi
7C93E078 FF75 08 push dword ptr [ebp+8]
7C93E07B 33DB xor ebx, ebx
7C93E07D 895D FC mov dword ptr [ebp-4], ebx
7C93E080 E8 B422FFFF call RtlImageNtHeader
7C93E085 8BF0 mov esi, eax
7C93E087 3BF3 cmp esi, ebx
7C93E089 0F84 17B10200 je 7C9691A6
7C93E08F 8B7E 34 mov edi, dword ptr [esi+34] ; [IMAGE_OPTIONAL_HEADER].ImageBase
7C93E092 8D45 FC lea eax, dword ptr [ebp-4]
7C93E095 50 push eax
7C93E096 6A 05 push 5
7C93E098 6A 01 push 1
7C93E09A FF75 08 push dword ptr [ebp+8] ; MZ基地址
7C93E09D 897D F8 mov dword ptr [ebp-8], edi
7C93E0A0 E8 A122FFFF call RtlImageDirectoryEntryToData ; 获得重定位数据
7C93E0A5 8BC8 mov ecx, eax
7C93E0A7 85C9 test ecx, ecx
7C93E0A9 74 54 je short 7C93E0FF
7C93E0AB 395D FC cmp dword ptr [ebp-4], ebx
7C93E0AE 74 4F je short 7C93E0FF
7C93E0B0 8B45 08 mov eax, dword ptr [ebp+8] ; MZ基地址
7C93E0B3 2BC7 sub eax, edi ; 执行体映像地址-建议加载地址
7C93E0B5 99 cdq
7C93E0B6 0345 0C add eax, dword ptr [ebp+C]
7C93E0B9 8BFA mov edi, edx
7C93E0BB 137D 10 adc edi, dword ptr [ebp+10]
7C93E0BE 8945 F0 mov dword ptr [ebp-10], eax ; delta = [ebp-010] = 执行体映像地址-建议加载地址
7C93E0C1 897D F4 mov dword ptr [ebp-C], edi
7C93E0C4 8B41 04 mov eax, dword ptr [ecx+4] ; ecx=重定位段地址
7C93E0C7 2945 FC sub dword ptr [ebp-4], eax ; 重定位段的大小
7C93E0CA 57 push edi
7C93E0CB FF75 F0 push dword ptr [ebp-10]
7C93E0CE 8D59 08 lea ebx, dword ptr [ecx+8] ; 重定位指针
7C93E0D1 8B09 mov ecx, dword ptr [ecx] ; RVA基地址
7C93E0D3 034D 08 add ecx, dword ptr [ebp+8] ; RAV+段基地址得到虚拟地址
7C93E0D6 8D70 F8 lea esi, dword ptr [eax-8] ; 重定位段大小-头大小8
7C93E0D9 53 push ebx ; 重定位项
7C93E0DA D1EE shr esi, 1 ; 除2,得到需要重定位项目的个数
7C93E0DC 56 push esi
7C93E0DD 51 push ecx ; 基地址指针
7C93E0DE E8 33000000 call 7C93E116 ; 这里就是重定位吧
7C93E0E3 8BC8 mov ecx, eax
7C93E0E5 85C9 test ecx, ecx
7C93E0E7 0F84 BCB00200 je 7C9691A9
7C93E0ED 837D FC 00 cmp dword ptr [ebp-4], 0
然后进入 Call 7c93e116..
具体重定位算法,呵呵。先看看下面重定位的组织方式吧:
void GetRelocInfo()
{
DWORD dwOffset=0;
UINT nIndex=1;
if( m_bIsValidPE && m_pOptionHeader ) {
//DataDirectory的第五项是重定位表
if ( m_pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0 &&
m_pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size == 0 ) {//重定位表为空
return;
}
dwOffset = GetFileOffset( m_pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress );
PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)(m_pFileBuf + dwOffset );
while ( pReloc->VirtualAddress ) {
RelocItem RI;
UINT i=0;
DWORD *pItem = (DWORD *)pReloc + 2;
WORD wOffset = 0;
ZeroMemory(&RI, sizeof(RelocItem) );
RI.nIndex = nIndex;
strcpy(RI.strSectionName , GetSectionName( pReloc->VirtualAddress ));//取所在区的名称
RI.nNum = (pReloc->SizeOfBlock-( sizeof(DWORD) << 1 ) ) /sizeof(WORD);//得到TypeOffset数量
while ( i < RI.nNum ) {
RelocChunk RC;
wOffset = (WORD) (*pItem);
switch( ( wOffset & 0xF000 ) >> 12 )
{//每个重定位项的类型
case IMAGE_REL_BASED_ABSOLUTE:
strcpy(RC.type , "ABSOLUTE(0)");
break;
case IMAGE_REL_BASED_HIGH:
strcpy(RC.type , "HIGH(1)");
break;
case IMAGE_REL_BASED_LOW:
strcpy(RC.type ,"LOW(2)");
break;
case IMAGE_REL_BASED_HIGHLOW:
strcpy(RC.type ,"HIGHLOW(3)");
break;
case IMAGE_REL_BASED_HIGHADJ:
strcpy(RC.type ,"HIGHADJ(4)");
break;
case IMAGE_REL_BASED_MIPS_JMPADDR:
strcpy(RC.type ,"JMPADDR(5)");
break;
/*case IMAGE_REL_BASED_MIPS_JMPADDR16:
RC.type = _T("JMPADDR16(9)");
break;*/
case IMAGE_REL_BASED_IA64_IMM64:
strcpy(RC.type ,"IMM64(9)");
break;
case IMAGE_REL_BASED_DIR64:
strcpy(RC.type ,"DIR64(10)");
break;
}
if( wOffset != 0 ) {
RC.dwRVA = pReloc->VirtualAddress+(wOffset&0x0FFF);
RC.dwFarAddr = * ( (DWORD*)( m_pFileBuf + GetFileOffset( RC.dwRVA ) ) );
}
else {//结束了的情况
RC.dwRVA = 0;
RC.dwFarAddr = 0;
}
RC.nIndex = ++i;//编号
// RI.chunk.push_back( RC );
pItem =(DWORD *)( (WORD*) pItem + 1 );//移到下一个Item
}
// m_reloc.push_back( RI );
pReloc=(PIMAGE_BASE_RELOCATION)((DWORD)pReloc + pReloc->SizeOfBlock);
}
}/*( m_bIsValidPE && m_pOptionHeader )*/
}
具体ntdll里面的汇编如下,很简单:
7C93E116 8BFF mov edi, edi
7C93E118 55 push ebp
7C93E119 8BEC mov ebp, esp
7C93E11B 51 push ecx
7C93E11C 51 push ecx
7C93E11D 837D 0C 00 cmp dword ptr [ebp+C], 0
7C93E121 53 push ebx
7C93E122 56 push esi
7C93E123 57 push edi
7C93E124 74 39 je short 7C93E15F
7C93E126 8B55 14 mov edx, dword ptr [ebp+14]
7C93E129 90 nop
7C93E12A 90 nop
7C93E12B 90 nop
7C93E12C 90 nop
7C93E12D 90 nop
7C93E12E 90 nop
7C93E12F 90 nop
7C93E130 8B75 10 mov esi, dword ptr [ebp+10] ; [ebp+010]重定位段指针
7C93E133 0FB706 movzx eax, word ptr [esi]
7C93E136 FF4D 0C dec dword ptr [ebp+C] ; [ebp+0c]需要重定位的个数
7C93E139 8BC8 mov ecx, eax
7C93E13B 81E1 FF0F0000 and ecx, 0FFF
7C93E141 034D 08 add ecx, dword ptr [ebp+8] ; 得到了需要重定位的地址咯。,[ebp+8]基地址指针
7C93E144 C1E8 0C shr eax, 0C
7C93E147 83F8 0A cmp eax, 0A
7C93E14A 77 1D ja short 7C93E169
7C93E14C FF2485 7DE4937C jmp dword ptr [eax*4+7C93E47D] ; eax==3,就修正,0就不修正
7C93E153 0111 add dword ptr [ecx], edx ; edx是delta..呵呵。。
7C93E155 8345 10 02 add dword ptr [ebp+10], 2
7C93E159 837D 0C 00 cmp dword ptr [ebp+C], 0
7C93E15D ^ 75 D1 jnz short 7C93E130
7C93E15F 8B45 10 mov eax, dword ptr [ebp+10]
7C93E162 5F pop edi
7C93E163 5E pop esi
7C93E164 5B pop ebx
7C93E165 C9 leave
7C93E166 C2 1400 retn 14
7C93E169 33C0 xor eax, eax
7C93E16B ^ EB F5 jmp short 7C93E162
--------------------------
分析就到这吧。。先睡哦。
Copy Right by lwglucky . QQ:14465340