[旧帖]
[求助]自己写的PE加载器碰到了一严重问题
0.00雪花
发表于:
2009-9-23 09:34
2740
[旧帖] [求助]自己写的PE加载器碰到了一严重问题
0.00雪花
下面是我写的加载器,可能有些杂乱
DWORD Load(wchar_t* name)
{
fstream f;
f.open(name, ios_base::in | ios_base::binary);
if (!f.is_open())
return 0;
//只是暂时获取头信息
char buff[1024];
DWORD currAddr = (DWORD)buff;
DWORD offset = 0;
f.read(buff, 1024);
IMAGE_DOS_HEADER dosHeader; //Dos头
IMAGE_NT_HEADERS ntHeader; //NT头
IMAGE_FILE_HEADER fileHeader; //文件头
IMAGE_OPTIONAL_HEADER optHeader;//可选头
IMAGE_DATA_DIRECTORY* pDataDir; //数据目录
IMAGE_IMPORT_DESCRIPTOR* pImportDes; //导入描述符
IMAGE_SECTION_HEADER* pSecHeader; //节头目录
//得到dos头,指针向前移动。
memcpy(&dosHeader, (void *)buff, sizeof(IMAGE_DOS_HEADER));
//初始化NT头
memcpy(&ntHeader, (void *)(buff + dosHeader.e_lfanew), sizeof(IMAGE_NT_HEADERS));
currAddr += dosHeader.e_lfanew;//当前地址指向NT头
//初始化文件头
memcpy(&fileHeader, (void *)(currAddr + sizeof(DWORD)), sizeof(IMAGE_FILE_HEADER));
currAddr += ( sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) );//当前地址指向可选头
//初始化可选头
memcpy(&optHeader, (void *)currAddr, sizeof(IMAGE_OPTIONAL_HEADER));
DWORD sectionAlignment = optHeader.SectionAlignment;
DWORD sizeOfImage = optHeader.SizeOfImage;
WORD nrOfSection = fileHeader.NumberOfSections;
currAddr += sizeof(IMAGE_OPTIONAL_HEADER); //指向节目录
pSecHeader = (IMAGE_SECTION_HEADER*)currAddr;
//将文件加载到内存
DWORD handle = (DWORD)new char[sizeOfImage];
memset((void*)handle, 0, sizeOfImage);
DWORD p = handle;
//将DOS头和DOS存根一起COPY
memcpy((void*)p, buff, dosHeader.e_lfanew);
p += dosHeader.e_lfanew;
//NT头
ntHeader.OptionalHeader.ImageBase = handle; //重写基地址
memcpy((void*)p, &ntHeader, sizeof(IMAGE_NT_HEADERS));
p += sizeof(IMAGE_NT_HEADERS);
//节表,直接从流中读取
offset = (DWORD)pSecHeader - (DWORD)buff;
f.seekg(offset);
f.read((char *)p, sizeof(IMAGE_SECTION_HEADER) * nrOfSection);
p += sizeof(IMAGE_SECTION_HEADER) * nrOfSection;
//装载节,从流中获取
for (int i = 0 ; i < nrOfSection ; i++)
{
f.seekg(pSecHeader[i].PointerToRawData);
f.read((char*)(handle + pSecHeader[i].VirtualAddress), pSecHeader[i].Misc.VirtualSize);
offset += pSecHeader[i].Misc.VirtualSize;
}
//初始化数据目录,输入表目录
//这里修改的都必须是new出来的空间里的数据
offset = dosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);//到OPT头
pDataDir = ((IMAGE_OPTIONAL_HEADER*)(handle + offset))->DataDirectory;
pImportDes = (IMAGE_IMPORT_DESCRIPTOR *)(handle + pDataDir[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
//所有节都装载完毕,重构导入表
for (int i = 0 ; pImportDes[i].Name != 0 ; i++)
{
HMODULE h = GetModuleHandleA((char *)(handle + pImportDes[i].Name));
if (!h)
{
h = LoadLibraryA((char *)(handle + pImportDes[i].Name));
if (!h)
continue;
}
//修正FirstTrunk使其指向导出函数的地址
IMAGE_THUNK_DATA32* pOriThunkData = (IMAGE_THUNK_DATA32*)(handle + pImportDes[i].OriginalFirstThunk);
IMAGE_THUNK_DATA32* pThunkData = (IMAGE_THUNK_DATA32*)(handle + pImportDes[i].FirstThunk);
for (int j = 0 ; pOriThunkData[j].u1.Ordinal != 0 ; j++)
{
//32位为1,THUNK表示HINT,否则表示函数名的RVA
if (pOriThunkData[j].u1.Ordinal & 0x80000000)
{
DWORD hint = pOriThunkData[j].u1.Ordinal & 0x7FFFFFFF;
pThunkData[j].u1.Function = GetProcAddrByHint((DWORD)h, hint);
}
else
{
IMAGE_IMPORT_BY_NAME* tmp = (IMAGE_IMPORT_BY_NAME*)(handle + pOriThunkData[j].u1.AddressOfData);
pThunkData[j].u1.Function = GetProcAddrByName((DWORD)h, (char*)(tmp->Name));
}
}
}
//输入表重构完毕
return handle;
}
DWORD GetProcAddrByHint(DWORD module, DWORD hint)
{
WORD index = 0;
IMAGE_EXPORT_DIRECTORY* pExpDir = NULL;
WORD* ordinals = NULL;
DWORD* addrFun = NULL;
DWORD offset = ((IMAGE_DOS_HEADER*)module)->e_lfanew;
pExpDir = (IMAGE_EXPORT_DIRECTORY*)(module + ((IMAGE_NT_HEADERS*)(module + offset))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
ordinals = (WORD*)((DWORD)module + pExpDir->AddressOfNameOrdinals);
addrFun = (DWORD*)((DWORD)module + pExpDir->AddressOfFunctions);
index = hint - pExpDir->Base;
index = ordinals[index];
return (DWORD)module + addrFun[index];
}
DWORD GetProcAddrByName(DWORD module, char* name)
{
int nr = 0;
WORD index = 0;
IMAGE_EXPORT_DIRECTORY* pExpDir = NULL;
WORD* ordinals = NULL;
DWORD* addrFun = NULL;
DWORD* names = NULL;
DWORD offset = ((IMAGE_DOS_HEADER*)module)->e_lfanew;
pExpDir = (IMAGE_EXPORT_DIRECTORY*)(module + ((IMAGE_NT_HEADERS*)(module + offset))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
ordinals = (WORD*)((DWORD)module + pExpDir->AddressOfNameOrdinals);
addrFun = (DWORD*)((DWORD)module + pExpDir->AddressOfFunctions);
names = (DWORD*)((DWORD)module + pExpDir->AddressOfNames);
nr = pExpDir->NumberOfNames;
for (int i = 0 ; i < nr ; i++)
{
if (!strcmp((char*)(module + names[i]),name))//equal
{
index = ordinals[i];
return (DWORD)module + addrFun[index];
}
}
return 0;
}
=======================================
这里是目标DLL
__declspec(dllexport) void __stdcall ofun()
{
// printf("%d",20);
}
=======================================
这里是主程序
DWORD h = Load(L"decorate name.dll");
// HMODULE h = LoadLibrary(L"decorate name.dll");
typedef void (*pfn)();
DWORD addr = GetProcAddrByName((DWORD)h, "?ofun@@YGXXZ");
pfn p = (pfn)addr;
p();
如果目标DLL的printf("%d",20)被注释掉了,那么p()的调用就OK(至少地址是对的)
如果printf没被注释掉,用我自己的LOAD加载DLL,在调用到printf时会出现访问异常,而使用系统的LOADLIBRARY则没问题,我看了下汇编代码:
00421078 55 push ebp
00421079 8B EC mov ebp,esp
0042107B 6A 14 push 14h
0042107D 68 4C 35 00 10 push 1000354Ch
00421082 FF 15 F0 61 00 10 call dword ptr ds:[100061F0h]
00421088 83 C4 08 add esp,8
0042108B 5D pop ebp
在call dword ptr ds:[100061F0h]处异常发生,DS此时=0;
下面是LOADLIBRARY:
10001010 55 push ebp
10001011 8B EC mov ebp,esp
10001013 6A 14 push 14h
10001015 68 4C 35 00 10 push offset ___xi_z+13Ch (1000354Ch)
1000101A FF 15 F0 61 00 10 call dword ptr [__imp__printf (100061F0h)]
10001020 83 C4 08 add esp,8
问题出在哪里,有人能告诉我吗?
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!