[原创]Load DLL from memory.
就是一个模拟加载DLL的
.
为了方便,代码里的DLL数据还是从文件里读的,实际应用的时候把文件缓冲区改成已经装备好的DLL数据就可以了。
PVOID PELoader_Dll(char *FileName); // 加载DLL
PVOID PeLoader_GetProcAddress(HMODULE imageBase,char *ExportName) ;导出函数名字
PELoader_Dll里面有一些printf输出信息,可以去掉,只是为了调试方便。
-------------------------------------------------------------------------------------
好了说说关于系统如何”识别“我们加载的DLL
我看了几篇帖子,争议很大呢,其实我们可以换一个角度想,让系统识别无非就是想用GetProcAddress或者FreeLibrary或者是DLLMain。
HOOK GetProcAddress,检查目标是不是我们加载的PE,如果是跳入我们的函数,不是则放行。
怎么检测?呵MZ标志后的一个字节放一个我们的标识码就好了。
FreeLibrary同上。
DLLMain:
这个也比较简单吧,随便HOOK某个DLL的DLLMain,然后跳入我们的DLLMain,然后又跳回去。
关于反HOOK.
重载内核很牛逼,重载DLL应该也不是什么难事,重写主模块的IAT. 所以InlneHOOK或者是IATHOOK都是浮云
以上为个人见解,不喜勿喷,写的不对的地方欢迎回帖。
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
// 定义
#define RvaToVa(base_,rva_) ((ULONG)base_+(ULONG)rva_)
//任意指针与整数相减
#define p_sub(s1,s2) ((ULONG)s1-(ULONG)s2)
//任意指针与整数相加
#define p_add(s1,s2) ((ULONG)s1+(ULONG)s2)
// jmp 指令操作码
#define jmp_opcode 0xe9
//计算jmp指令操作数
#define calc_jmpaddr(n,d) (((unsigned int)d-(unsigned int)n)-5)
typedef BOOL (WINAPI *ptrDllMain) (
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved // reserved
);
//-------------------------------------------------------------------------------------------------------------------------------------------
void FixBaseRelocTable(PVOID pNewImage)
{
ULONG uIndex;
ULONG uRelocTableSize;
ULONG OriginalImageBase;
ULONG Type;
ULONG *uRelocAddress;
ULONG OrigImage;
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeader;
IMAGE_DATA_DIRECTORY ImageDataDirectory;
IMAGE_BASE_RELOCATION *pImageBaseRelocation;
//将新内核地址作为一个PE文件头,依次向下,目的是寻找重定位表结构
pImageDosHeader=(PIMAGE_DOS_HEADER)pNewImage;
//定位到IMAGE_NT_HEADER
pImageNtHeader=(PIMAGE_NT_HEADERS)((ULONG)pNewImage+pImageDosHeader->e_lfanew);
//获取内核文件的imagebase,以便后面做偏移修改。
OriginalImageBase=pImageNtHeader->OptionalHeader.ImageBase;
//定位到数据目录
ImageDataDirectory = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
//定位到重定位表结构
pImageBaseRelocation = (PIMAGE_BASE_RELOCATION)(ImageDataDirectory.VirtualAddress + (ULONG)pNewImage);
//得到源基址
OrigImage = pImageNtHeader->OptionalHeader.ImageBase;
if (pImageBaseRelocation==NULL)
{
return;
}
while (pImageBaseRelocation->SizeOfBlock)
{ //计算需要修改的地址的个数
uRelocTableSize=(pImageBaseRelocation->SizeOfBlock-8)/2;
//循环遍历
for (uIndex=0;uIndex<uRelocTableSize;uIndex++)
{//判断高4位是否等于3
Type=pImageBaseRelocation->TypeOffset[uIndex]>>12;
if (Type==3)
{
//修改地址
ULONG old;
uRelocAddress=(ULONG *)((ULONG)(pImageBaseRelocation->TypeOffset[uIndex]&0x0fff)+pImageBaseRelocation->VirtualAddress+(ULONG)pNewImage);
old = *uRelocAddress;
*uRelocAddress=*uRelocAddress+p_sub(pNewImage,OriginalImageBase);
printf("重定位处理 块:%x index:%x 未定位:%x 已定位:%x\n",pImageBaseRelocation->VirtualAddress,uIndex,old,*uRelocAddress);
}
}
//进行下一个重定位表的修改
pImageBaseRelocation=(IMAGE_BASE_RELOCATION *)((ULONG)pImageBaseRelocation+pImageBaseRelocation->SizeOfBlock);
}
}
PVOID PELoader_Dll(char *FileName)
{
FILE *fp;
IMAGE_DOS_HEADER stDosHead;
IMAGE_NT_HEADERS stNtHead;
ULONG Imagebase;
char *image_mem; // 内存中的镜像地址.
fp=fopen(FileName,"rb+");
if(fp==NULL) return false;
fread(&stDosHead,sizeof(IMAGE_DOS_HEADER),1,fp);
if (stDosHead.e_magic!=IMAGE_DOS_SIGNATURE) {err:fclose(fp);return false;}
fseek(fp,stDosHead.e_lfanew,SEEK_SET);
fread(&stNtHead,sizeof(IMAGE_NT_HEADERS),1,fp);
if(stNtHead.Signature!=IMAGE_NT_SIGNATURE)goto err;
Imagebase=stNtHead.OptionalHeader.ImageBase;
//申请镜像空间
//image_mem = new char[stNtHead.OptionalHeader.SizeOfImage];
image_mem=(char *)VirtualAlloc(NULL,stNtHead.OptionalHeader.SizeOfImage,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
//---------------------------------------------------------
if(!image_mem) goto err;
//拷贝数据到镜像空间
memcpy(image_mem,&stDosHead,sizeof(IMAGE_DOS_HEADER));
memcpy(&image_mem[stDosHead.e_lfanew],&stNtHead,sizeof(IMAGE_NT_HEADERS));
printf("加载基址:%x\n默认基址:%x\n",image_mem,Imagebase);
//区块表
PIMAGE_SECTION_HEADER sections;
sections = (PIMAGE_SECTION_HEADER)&image_mem[stDosHead.e_lfanew+sizeof(IMAGE_NT_HEADERS)];
fread(sections,sizeof(IMAGE_SECTION_HEADER),stNtHead.FileHeader.NumberOfSections,fp);
for (ULONG i=0;i<stNtHead.FileHeader.NumberOfSections;i++)
{
char *pSecData;
pSecData=&image_mem[sections[i].VirtualAddress];
fseek(fp,sections[i].PointerToRawData,SEEK_SET);
fread(pSecData,sections[i].SizeOfRawData,1,fp);
}
//处理导入表
PIMAGE_IMPORT_DESCRIPTOR pImport;
IMAGE_IMPORT_DESCRIPTOR null_immport={0};
pImport=(PIMAGE_IMPORT_DESCRIPTOR)RvaToVa(image_mem,stNtHead.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (memcmp(pImport,&null_immport,sizeof(IMAGE_IMPORT_DESCRIPTOR)))
{
char *DllName;
HMODULE hmodule;
DllName = (char *)RvaToVa(image_mem,pImport->Name);
hmodule=GetModuleHandleA(DllName);
//加载所需要的模块
if(!hmodule)
{
hmodule=LoadLibraryA(DllName);
if(!hmodule)
{
printf("无法加载:%s\n",DllName);
err2:
//擦屁股
fclose(fp);
VirtualFree( image_mem,stNtHead.OptionalHeader.SizeOfImage,MEM_RELEASE);
return NULL;
}
}
printf("正在加载:%s\n",DllName);
//填充IAT表
PVOID AddressOfFunction;
PIMAGE_THUNK_DATA thunk;
DWORD *IAT;
thunk =(PIMAGE_THUNK_DATA) RvaToVa(image_mem,pImport->OriginalFirstThunk);
IAT=(DWORD *)RvaToVa(image_mem,pImport->FirstThunk);
while (thunk->u1.AddressOfData)
{
DWORD test;
char *strApiName;
test = *(DWORD *)thunk;
PIMAGE_IMPORT_BY_NAME ApiName;
if(test&IMAGE_ORDINAL_FLAG32)
{
//按序号导入
test&=0xffff;//去掉高16位
printf("[ %s ]按序号导入函数:%d 加载失败!\n",DllName,test);
goto err2;
}
ApiName=(PIMAGE_IMPORT_BY_NAME)RvaToVa(image_mem,thunk->u1.AddressOfData);
strApiName=(char *)&ApiName->Name;
AddressOfFunction = GetProcAddress(hmodule,strApiName);
if (!AddressOfFunction)
{
printf("加载 [ %s ] 时发现未导出函数:%s\n",DllName,strApiName);
goto err2;
}
//填充IAT
printf("\t%s Address:%x IAT:%x\n",strApiName,AddressOfFunction,IAT);
*(DWORD *)IAT = (DWORD)AddressOfFunction;
thunk++;
IAT++;
}
pImport++;
}
// 处理导出表
DWORD baseorder; // 起始序号
PIMAGE_EXPORT_DIRECTORY pExport;
WORD *Ord;
DWORD *FunAddr;
DWORD *name_list;
pExport=(PIMAGE_EXPORT_DIRECTORY)RvaToVa(image_mem,stNtHead.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
baseorder = pExport->Base;
Ord=(WORD *)RvaToVa(image_mem,pExport->AddressOfNameOrdinals);
FunAddr=(DWORD *)RvaToVa(image_mem,pExport->AddressOfFunctions);
name_list = (DWORD *)RvaToVa(image_mem,pExport->AddressOfNames);
for (DWORD i=0;i<pExport->NumberOfFunctions;i++)
{
DWORD Index;
DWORD FunRva;
char *FunName;
FunName = (char *)RvaToVa(image_mem,name_list[i]);
//填充
Index=Ord[i];
//Index+=baseorder;
FunRva=FunAddr[Index];
printf("导出函数:%s Rva:%x\n",FunName,FunRva);
FunRva+=(DWORD)image_mem;
FunAddr[i]=FunRva;
}
//重定位表
FixBaseRelocTable(image_mem);
//创建标记
image_mem[3]='X';
//通知DLL已经被加载
ptrDllMain DllMain1;
DllMain1 = (ptrDllMain)RvaToVa(image_mem,stNtHead.OptionalHeader.AddressOfEntryPoint);
DllMain1((HINSTANCE)image_mem,DLL_PROCESS_ATTACH,0);
DllMain1((HINSTANCE)image_mem,DLL_THREAD_ATTACH,0);
return image_mem;
}
PVOID PeLoader_GetProcAddress(HMODULE imageBase,char *ExportName)
{
PIMAGE_DOS_HEADER pDosHead;
PIMAGE_NT_HEADERS pNtHead;
PIMAGE_EXPORT_DIRECTORY pExport;
WORD *Ord;
DWORD *FunAddr;
DWORD *name_list;
DWORD baseorder;
char *data;
//先对PE文件进行验证,是否为模拟加载
pDosHead = (PIMAGE_DOS_HEADER)imageBase;
pNtHead = (PIMAGE_NT_HEADERS)p_add(imageBase,pDosHead->e_lfanew);
pExport=(PIMAGE_EXPORT_DIRECTORY)RvaToVa(imageBase,pNtHead->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
baseorder = pExport->Base;
Ord=(WORD *)RvaToVa(imageBase,pExport->AddressOfNameOrdinals);
FunAddr=(DWORD *)RvaToVa(imageBase,pExport->AddressOfFunctions);
name_list = (DWORD *)RvaToVa(imageBase,pExport->AddressOfNames);
for (DWORD i=0;i<pExport->NumberOfFunctions;i++)
{
DWORD Index;
DWORD FunRva;
char *FunName;
FunName = (char *)RvaToVa(imageBase,name_list[i]);
if (!strcmp(FunName,ExportName))
{
Index=Ord[i];
//Index+=baseorder;
FunRva=FunAddr[Index];
return (PVOID *)FunRva;
}
}
return NULL;
}
void main()
{
HMODULE dllbase;
char *f1;
printf("PE Loader..... \n");
dllbase=(HMODULE )PELoader_Dll("C:\\Hello.dll");
f1 = (char *)PeLoader_GetProcAddress(dllbase,"fun2");
getchar();
}
