合并DLLWord下载.docx
《合并DLLWord下载.docx》由会员分享,可在线阅读,更多相关《合并DLLWord下载.docx(15页珍藏版)》请在冰豆网上搜索。
程序实现。
首先,把要合并的DLL作为资源加入到项目的资源文件中,然后在程序运行时,从资源中载入该资源,以得到该DLL在内存中的位置:
LPVOIDsRawDll;
//资源文件在内存中的地址
HRSRChRes;
HMODULEhLibrary;
HGLOBALhResourceLoaded;
charlib_name[MAX_PATH];
GetModuleFileName(hInstance,lib_name,MAX_PATH);
//得到运行程序的名字
hLibrary=LoadLibrary(lib_name);
//就象载入一个DLL一样载入运行程序到内存中
if(NULL!
=hLibrary)
{
//得到指定的资源文件在内存中的位置
hRes=FindResource(hLibrary,MAKEINTRESOURCE(IDR_DATA1),RT_RCDATA);
if(NULL!
=hRes)
{
//将资源文件载入内存
hResourceLoaded=LoadResource(hLibrary,hRes);
if(NULL!
=hResourceLoaded)&
nbsp;
{
//得到资源文件大小
SizeofResource(hLibrary,hRes);
//锁定资源以得到它在内存中的地址
sRawDll=(LPVOID)LockResource(hResourceLoaded);
}
}
elsereturn1;
FreeLibrary(hLibrary);
}
elsereturn1;
然后,从资源中载入DLL到内存函数LoadPbDllFromMemory将载入DLL到内存中,该函数有两个参数,第一个参数是指向DLL资源在内存中的地址的指针,也就是前面代码中的LockResource函数的返回值。
第二个参数是一个空的指针,如果函数LoadPbDllFromMemory运行成功,该指针将指向重新组合后的内存中的DLL的起始地址。
该函数还有一个功能就是如果运行成功,它将手动地用DLL_PROCESS_ATTACH参数调用DLL的入口函数DllMain来初始化该DLL。
除此之外,它还会手动地载入合并的DLL的入口表中导入的DLL并调整它们在内存中的相对地址。
以下是该函数代码:
DWORDLoadPbDllFromMemory(LPVOIDlpRawDll,LPVOIDlpImageDll)
SYSTEM_INFOsSysInfo;
PIMAGE_DOS_HEADERdosHeader;
PIMAGE_NT_HEADERSpNTHeader;
PIMAGE_SECTION_HEADERsection;
PIMAGE_IMPORT_DESCRIPTORpImportDesc;
PIMAGE_IMPORT_BY_NAMEpOrdinalName;
PIMAGE_BASE_RELOCATIONbaseReloc;
PDWORDlpLink;
unsignedcharProtection[4096];
HINSTANCEhDll;
WORDi;
DWORDImagePages,fOldProtect,j,MaxLen,HdrLen,Addr1,Addr2,Pg,Pg1,Pg2;
char*sDllName;
if(NULL==lpRawDll)return1;
dosHeader=(PIMAGE_DOS_HEADER)lpRawDll;
//IsthistheMZheader?
if((TRUE==IsBadReadPtr(dosHeader,sizeof(IMAGE_DOS_HEADER)))||
(IMAGE_DOS_SIGNATURE!
=dosHeader->
e_magic))&
return2;
//GetthePEheader.
pNTHeader=MakePtr(PIMAGE_NT_HEADERS,dosHeader,dosHeader->
e_lfanew);
//IsthisarealPEimage?
if((TRUE==IsBadReadPtr(pNTHeader,sizeof(IMAGE_NT_HEADERS)))||
(IMAGE_NT_SIGNATURE!
=pNTHeader->
Signature))
return3;
if((pNTHeader->
FileHeader.SizeOfOptionalHeader!
=
sizeof(pNTHeader->
OptionalHeader))||
(pNTHeader->
OptionalHeader.Magic!
=IMAGE_NT_OPTIONAL_HDR32_MAGIC))
return4;
if(pNTHeader->
FileHeader.NumberOfSections<
1)return5;
section=IMAGE_FIRST_SECTION(pNTHeader);
intHeaderSize=sizeof(IMAGE_SECTION_HEADER);
//节头长度
HdrLen=(DWORD)section-(DWORD)dosHeader+
HeaderSize*pNTHeader->
FileHeader.NumberOfSections;
//找出最大的节的长度,此节一般是代码所在的节(.text节)
MaxLen=HdrLen;
intii=0;
for(i=0;
i<
(DWORD)pNTHeader->
i++)//findMaxLen
if(MaxLen<
section[i].VirtualAddress+section[i].SizeOfRawData)
MaxLen=section[i].VirtualAddress+section[i].SizeOfRawData;
if(strcmp((constchar*)section[i].Name,"
.rsrc"
)==0)ii=i;
GetSystemInfo(&
sSysInfo);
ImagePages=MaxLen/sSysInfo.dwPageSize;
if(MaxLen%sSysInfo.dwPageSize)ImagePages++;
//分配所需的内存
DWORDNeededMemory=ImagePages*sSysInfo.dwPageSize;
lpImageDll=VirtualAlloc(NULL,NeededMemory,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(lpImageDll==NULL)return6;
//分配内存失败
MoveMemory(lpImageDll,lpRawDll,HdrLen);
//复制节头
DWORDOrgAddr=0;
DWORDNewAddr=0;
DWORDSize=0;
//复制.text节数据
iFileHeader.NumberOfSections;
i++)
OrgAddr=(DWORD)lpImageDll+(DWORD)section[i].VirtualAddress;
NewAddr=(DWORD)lpRawDll+(DWORD)section[i].PointerToRawData;
Size=(DWORD)section[i].SizeOfRawData;
MoveMemory((void*)OrgAddr,(void*)NewAddr,Size);
//把指针指向新的DLL映像
dosHeader=(PIMAGE_DOS_HEADER)lpImageDll;
//Switchtonewimage
pNTHeader=(PIMAGE_NT_HEADERS)((DWORD)dosHeader+dosHeader->
section=(PIMAGE_SECTION_HEADER)((DWORD)pNTHeader+sizeof(IMAGE_NT_HEADERS));
pImageBase=(PBYTE)dosHeader;
if((ii!
=0)&
&
(IsNT()==TRUE))
section[ii].VirtualAddress=section[ii].VirtualAddress+(DWORD)lpRawDll;
section[ii].PointerToRawData=section[ii].PointerToRawData+(DWORD)lpRawDll;
DWORDimportsStartRVA;
//Lookupwheretheimportssectionis(normallyinthe.idatasection)
//butnotnecessarilyso.Therefore,grabtheRVAfromthedatadir.
importsStartRVA=GetImgDirEntryRVA(pNTHeader,IMAGE_DIRECTORY_ENTRY_IMPORT);
if(!
importsStartRVA)&
VirtualFree(dosHeader,0,MEM_RELEASE);
return7;
pImportDesc=(PIMAGE_IMPORT_DESCRIPTOR)pNTHeader->
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if(pImportDesc!
=0)
pImportDesc=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pImportDesc+(DWORD)dosHeader);
else&
return8;
while
(1)//处理各入口表中的DLL
//检查是否遇到了空的IMAGE_IMPORT_DESCRIPTOR
if((pImportDesc->
TimeDateStamp==0)&
(pImportDesc->
Name==0))break;
//从磁盘载入必须的Dll,
//注意,载入的DLL是合并的DLL的入口表中的DLL,
//不是合并到EXE中的DLL
sDllName=(char*)(pImportDesc->
Name+(DWORD)pImageBase);
hDll=GetModuleHandle(sDllName);
if(hDll==0)hDll=LoadLibrary(sDllName);
if(hDll==0)
MessageBox(NULL,"
Can'
'
tfindrequiredDll"
"
ErrorinLoadPbDllFromMemory()"
0);
VirtualFree(dosHeader,0,MEM_RELEASE);
return9;
DWORD*lpFuncNameRef=(DWORD*)(pImportDesc->
OriginalFirstThunk+
(DWORD)dosHeader);
DWORD*lpFuncAddr=(DWORD*)(pImportDesc->
FirstThunk+
while(*lpFuncNameRef!
pOrdinalName=(PIMAGE_IMPORT_BY_NAME)(*lpFuncNameRef+
(DWORD)dosHeader);
DWORDpIMAGE_ORDINAL_FLAG=0x80000000;
if(*lpFuncNameRef&
pIMAGE_ORDINAL_FLAG)
*lpFuncAddr=(DWORD)GetProcAddress(hDll,
(constchar*)(*lpFuncNameRef&
0xFFFF));
else
(constchar*)pOrdinalName->
Name);
if(lpFuncAddr==0)&
{
VirtualFree(dosHeader,0,MEM_RELEASE);
return10;
//Can'
tGetProcAddress
}
lpFuncAddr++;
lpFuncNameRef++;
pImportDesc++;
DWORDTpOffset;
baseReloc=(PIMAGE_BASE_RELOCATION)((DWORD)pNTHeader->
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
if(baseReloc!
=0)
baseReloc=(PIMAGE_BASE_RELOCATION)((DWORD)baseReloc+(DWORD)dosHeader);
while(baseReloc->
VirtualAddress!
PWORDlpTypeOffset=(PWORD)((DWORD)baseReloc+
sizeof(IMAGE_BASE_RELOCATION));
while(lpTypeOffset<
(PWORD)((DWORD)baseReloc+
(DWORD)baseReloc->
SizeOfBlock))
TpOffset=*lpTypeOffset&
0xF000;
if(TpOffset==0x3000)
{
lpLink=(PDWORD)((DWORD)dosHeader+baseReloc->
VirtualAddress+
(*lpTypeOffset&
0xFFF));
*lpLink=(DWORD)dosHeader+(*lpLink)-
pNTHeader->
OptionalHeader.ImageBase;
}
else
if(TpOffset!
=0)&
{
VirtualFree(dosHeader,0,MEM_RELEASE);
return10;
}
lpTypeOffset++;
baseReloc=(PIMAGE_BASE_RELOCATION)((DWORD)baseReloc+
(DWORD)baseReloc->
SizeOfBlock);
//取得原始的内存状态
memset(Protection,0,4096);
=pNTHeader->
if(i==pNTHeader->
FileHeader.NumberOfSections)
Addr1=0;
Addr2=HdrLen;
j=0x60000000;
else
Addr1=section[i].VirtualAddress;
Addr2=section[i].SizeOfRawData;
j=section[i].Characteristics;
Addr2+=Addr1-1;
Pg1=Addr1/sSysInfo.dwPageSize;
Pg2=Addr2/sSysInfo.dwPageSize;
for(Pg=Pg1;
Pg<
=Pg2;
Pg++)
if(j&
0x20000000)Protection[Pg]|=1;
//Execute
0x40000000)Protection[Pg]|=2;
//Read
0x80000000)Protection[Pg]|=4;
//Write
//恢复原始的内存状态
Addr1=(DWORD)dosHeader;
for(Pg=0;
=ImagePages;
switch(Protection[Pg])
case2:
fOldProtect=PAGE_READONLY;
break;
case3:
fOldProtect=PAGE_EXECUTE_READ;
case6:
fOldProtect=PAGE_READWRITE;
default:
//Ignorestrangecombinations
fOldProtect=PAGE_EXECUTE_READWRITE;
if(fOldProtect!
=PAGE_EXECUTE_READWRITE)
if(VirtualProtect((void*)Addr1,
sSysInfo.dwPageSize,
fOldProtect,
&
fOldProtect)==0)
return11;
Addr1+=sSysInfo.dwPageSize;
EntryPoint=(LPENTRYPOINT)((DWORD)pNTHeader->
OptionalHeader.AddressOfEntryPoint+
(DWORD)dosHeader);
LPVOIDlpReserved=0;
EntryPoint((HINSTANCE)dosHeader,DLL_PROCESS_ATTACH,lpReserved);
lpImageDll2=lpImageDll;
return0;
一但DLL被正确地载入到内存中,我们就可以通过自定义函数GetProcAddressDirectly来获取某函数在内存中的地址,并根据该地址来调用该函数,该函数也有两个参数,第一个参数是指向载入到内存中的DLL的起始地址的指针,第二个是要调用的函数的函数名。
以下是GetProcAddressDirectly函数代码:
DWORDGetProcAddressDirectly(PIMAGE_DOS_HEADERdosHeader,char*FuncName)
{
PIMAGE_NT_HEADERSpNTHead