欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Load DLL from memory.

[原创]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();

}

上传的附件 PeLoader.zip

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功