首页
论坛
课程
招聘
酒色财气
雪    币: 179
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:110 )
在线值:
发帖
18
回帖
140
粉丝
0

[原创]内存加载user32.dll 运行 附源码

2011-9-27 14:39 8346

[原创]内存加载user32.dll 运行 附源码

2011-9-27 14:39
8346
看到有人说LoadLibrary("user32.dll"),360要报。(我自己试了下,没报饿。不知道为啥);

于是就有想可不可以内存加载然后运行。
思路很简单:
1:以PE方式把user32.dll(或者其它dll)COPY到程序中。
2:通过重写位表,进行重定位。
3:解决输入表问题。
4:DLL初始化一下。

完成上面4步就可以调用了。我测试的MessageBoxA,没有问题。
后来仔细想想360肯定是HOOK的内核函数,所以好像这样没用。
// CopySysDll.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <TCHAR.H>
#include <STDLIB.H>

DWORD g_dwRelocSecAddr = 0;
DWORD g_dwOriginalLoadBase = 0;
DWORD g_dwRelocSecSize = 0;
DWORD g_dwDllMain = 0;
BOOL IsPeFromHandle( HANDLE hFile )
{
	DWORD dwReadBuf;
	DWORD dwPeFlagOffset;
	// 读PE头RAW
	SetFilePointer( hFile, 0x3c, NULL, FILE_BEGIN );
	ReadFile( hFile, &dwPeFlagOffset, 4, &dwReadBuf, NULL );
	// 读取PE标志
	SetFilePointer( hFile, dwPeFlagOffset, NULL, FILE_BEGIN );
	ReadFile( hFile, &dwPeFlagOffset, 2, &dwReadBuf, NULL );
	if ( 0x4550 == dwPeFlagOffset )
		return TRUE;
	else
		return FALSE;
}

DWORD LoadFile( HANDLE hFile )
{
	DWORD dwNumOfSections;
	DWORD dwPeFlagOffset;			// PE文件标志偏移
	DWORD dwReadBuf;			 // 实际读取的字节数
	DWORD dwSizeOfHeaders;		     // PE头的总大小
	DWORD dwSizeOfImage;

	if ( !IsPeFromHandle( hFile ) )
		return 0;
	
	// 读PE头RAW
	SetFilePointer( hFile, 0x3c, NULL, FILE_BEGIN );
	ReadFile( hFile, &dwPeFlagOffset, 4, &dwReadBuf, NULL );
	// 读取映像装入内存后总尺寸
	SetFilePointer( hFile, dwPeFlagOffset+0x50, NULL, FILE_BEGIN ); 
	ReadFile( hFile, &dwSizeOfImage, 4, &dwReadBuf, NULL );
	// 读取pe头的总大小
	SetFilePointer( hFile, dwPeFlagOffset+0x54, NULL, FILE_BEGIN );
	ReadFile( hFile, &dwSizeOfHeaders, 4, &dwReadBuf, NULL );
	
	// 分配内存来装载文件
	 LPVOID lpBase = VirtualAlloc( NULL, dwSizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
	
	// 读PE文件头
	SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
	ReadFile( hFile, lpBase, dwSizeOfHeaders, &dwReadBuf, NULL );
	// 得到PE文件相关指针
	PIMAGE_DOS_HEADER pDosHeaders = (PIMAGE_DOS_HEADER) lpBase;
	PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) ( pDosHeaders->e_lfanew + (DWORD) pDosHeaders );
	PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER) &( pNtHeaders->OptionalHeader );
	PIMAGE_SECTION_HEADER pSecHaeder = IMAGE_FIRST_SECTION( pNtHeaders );
	g_dwOriginalLoadBase = pOptionalHeader->ImageBase; 
	g_dwDllMain = pOptionalHeader->AddressOfEntryPoint + (DWORD)lpBase;
	// 分区块读入内存
	dwNumOfSections = pNtHeaders->FileHeader.NumberOfSections;
	for ( DWORD i = 0; i < dwNumOfSections; i++ )
	{
		DWORD dwOff = SetFilePointer( hFile, (pSecHaeder + i)->PointerToRawData, NULL, FILE_BEGIN );
		BOOL bret = ReadFile( hFile, LPVOID( (pSecHaeder+ i)->VirtualAddress + (DWORD)lpBase), (pSecHaeder+i)->SizeOfRawData,
			&dwReadBuf, NULL );
		if ( i == dwNumOfSections - 1 )
		{
			g_dwRelocSecAddr = (DWORD) ( (pSecHaeder+ i)->VirtualAddress + (DWORD)lpBase);
			g_dwRelocSecSize = (DWORD) ( (pSecHaeder + i)->Misc.VirtualSize );
		}
			
	}	
	return (DWORD)lpBase;
}

// 修正重定位表
void Relocation( DWORD dwBase )
{
	// 得到实际加载地址和默认加载地址的差值
	DWORD dwNum;
	dwNum = dwBase - g_dwOriginalLoadBase;
	
	DWORD dwMax = g_dwRelocSecAddr + g_dwRelocSecSize;

	while ( g_dwRelocSecAddr < dwMax )
	{
		DWORD dwRelocRva = *( (DWORD*) g_dwRelocSecAddr );
		g_dwRelocSecAddr += 4; 
		DWORD dwRelocSize = *( (DWORD*) g_dwRelocSecAddr );
		g_dwRelocSecAddr += 4;
		// 去悼基址和大小占用的字节,一个重定位数据是2字节。/2得到这组重定个数
		dwRelocSize -= 8;
		dwRelocSize /= 2;
		

		WORD wRelocInfo= 0;					   // 重定位信息
		WORD wBak = 0;			
		DWORD dwDataAddr = 0;			// 重定位数据的地址
		DWORD dwData = 0;						   // 重定位地址的内容
		for ( DWORD i = 0; i < dwRelocSize; i++ )
		{
			wRelocInfo = *(WORD*)g_dwRelocSecAddr;
			g_dwRelocSecAddr += 2;

			wBak = wRelocInfo;
			wBak = wBak>>12;
			
			// IMAGE_REL_BASED_HIGHLOW 常量是3,表示重定位整个地址都要修正
			if ( wBak == IMAGE_REL_BASED_HIGHLOW )
			{
				// 得到低12位
				wRelocInfo = wRelocInfo & 0x0fff;
				dwDataAddr = dwBase + wRelocInfo + dwRelocRva;
				// 读出数据
				dwData = *(DWORD*)dwDataAddr;
				dwData = dwData + dwNum;
				// 写入数据,完成重定位
				*(DWORD*)dwDataAddr = dwData;
			}
		}
	}
}

// 修正输入表函数地址
void UpdateImportTableAddress( DWORD dwBase )
{
	// 得到输入表IID结构
	// 得到PE文件相关指针
	PIMAGE_DOS_HEADER pDosHeaders = (PIMAGE_DOS_HEADER) dwBase;
	PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS) ( pDosHeaders->e_lfanew + (DWORD) pDosHeaders );
	PIMAGE_OPTIONAL_HEADER pOptionalHeader = (PIMAGE_OPTIONAL_HEADER) &( pNtHeaders->OptionalHeader );
	PIMAGE_SECTION_HEADER pSecHaeder = IMAGE_FIRST_SECTION( pNtHeaders );
	
	// 得到输入表
	PIMAGE_DATA_DIRECTORY pImaDataDir = &( pOptionalHeader->DataDirectory[1] );
	PIMAGE_IMPORT_DESCRIPTOR lpImportTab =(PIMAGE_IMPORT_DESCRIPTOR) LPVOID ( pImaDataDir->VirtualAddress + dwBase );
	PIMAGE_IMPORT_DESCRIPTOR lpImportTabBak = lpImportTab;
	
	DWORD dwNameAddr = 0;
	DWORD dwFunAddr = 0;

	while ( 0 != lpImportTab->Name )
	{
		HMODULE hMod = GetModuleHandle( (LPCTSTR)(DWORD*)(dwBase+lpImportTab->Name) );
		if ( !hMod )
		{
			hMod = LoadLibrary( (LPCTSTR)(DWORD*)(dwBase+lpImportTab->Name) );
		}
			
		// 取得INT OR IAT结构的RAV
		DWORD* pdwINTRav;
		DWORD* pdwIATRav;
		pdwIATRav = (DWORD*) ( (DWORD)dwBase+ lpImportTab->FirstThunk );
		if ( lpImportTab->OriginalFirstThunk != 0 )
			pdwINTRav = (DWORD*) ( (DWORD)dwBase+ lpImportTab->OriginalFirstThunk );
		else
			pdwINTRav = (DWORD*) ( (DWORD)dwBase+ lpImportTab->FirstThunk );
		
		// 函数名方式得到地址
		while ( 0 != *pdwINTRav )
		{
			if ( 0x80000000 > *pdwINTRav )
			{
					// dwNameAddr是IMAGE_IMPORT_BY_NAME结构地址,+2的地方就是函数名字串
					dwNameAddr = *pdwINTRav + dwBase;
					dwFunAddr = (DWORD)GetProcAddress( hMod, (LPCTSTR)(DWORD*)(dwNameAddr+2) );
					*pdwIATRav = dwFunAddr;
					++pdwINTRav;
					++pdwIATRav;
			}
			// 序列号方式
			else
			{	
				// 得到函数序列号
				DWORD dwSerialNunOfFun;
				dwSerialNunOfFun = *pdwINTRav ^ 0x80000000;
				DWORD dwFunAddr = (DWORD)GetProcAddress( hMod, (LPCTSTR)(DWORD*)dwSerialNunOfFun );
				*pdwIATRav = dwFunAddr;
				++pdwINTRav;
				++pdwIATRav;
			}	// endif else	
		} // end while
		++lpImportTab;
	}	// end while
}

FARPROC MyGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
	PIMAGE_DOS_HEADER pDOSHeader;
	PIMAGE_NT_HEADERS pNTHeader;
	PIMAGE_EXPORT_DIRECTORY pExportDir;
	LPCSTR *pFunctionName; 
	LPCSTR pszFunName;
	LPDWORD pFunction;
	LPWORD pIndex;
	DWORD n; 
	FARPROC ret = NULL;
	if ((INVALID_HANDLE_VALUE == hModule) || (NULL == lpProcName))
	{
		goto end;
	}
	pDOSHeader = (PIMAGE_DOS_HEADER)hModule;
	if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)  
	{
		goto end;
	}
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader + (DWORD)pDOSHeader->e_lfanew);
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) 
	{
		goto end;
	}
	pExportDir = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pDOSHeader + \
		(DWORD)pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	if ((DWORD)pExportDir == (DWORD)pDOSHeader) 
	{
		goto end;
	}
	pFunctionName = (LPCSTR *)((DWORD)pExportDir->AddressOfNames + (DWORD)pDOSHeader);
	pFunction = (LPDWORD)((DWORD)pExportDir->AddressOfFunctions + (DWORD)pDOSHeader);
	pIndex = (LPWORD)((DWORD)pExportDir->AddressOfNameOrdinals + (DWORD)pDOSHeader);
	n = pExportDir->NumberOfNames;
	while (n--)
	{
		pszFunName = (LPCSTR)((DWORD)*pFunctionName + (DWORD)pDOSHeader);
		if (strcmp(pszFunName, lpProcName) == 0)
		{
			ret = (FARPROC)(pFunction[*pIndex] + (DWORD)pDOSHeader);
			break;
		}
		pFunctionName++;
		pIndex++;
	}
end:	
	return ret;
}

typedef int ( __stdcall *MyMessageBoxA)( HANDLE, LPCSTR, LPCSTR, UINT );

int main(int argc, char* argv[])
{
	MessageBox( NULL, _T("现在我在user.dll中"), _T("提示"), MB_OK );
	TCHAR szSysPathBuffer[MAX_PATH];
	int bRet = GetSystemDirectory( szSysPathBuffer, MAX_PATH );
	if ( 0 != bRet )
	{
		_tcscat( szSysPathBuffer, _T("\\User32.dll") );
	}
	HANDLE hFile = CreateFile( szSysPathBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
	LPVOID lpBase = (LPVOID)LoadFile( hFile );
	// 修正重定位
	Relocation( (DWORD)lpBase );
	// 修正输入表
	UpdateImportTableAddress( (DWORD)lpBase );
	// DLL初始化
	__asm
	{
		pushad
		push 0
		push DLL_PROCESS_ATTACH
		push lpBase
		mov eax, g_dwDllMain
		call eax
		popad
	}
	
	// 哈哈全部完成现在测试下
	HMODULE hMod = (HMODULE)(DWORD)lpBase;
	MyMessageBoxA Fun;
	Fun = (MyMessageBoxA)MyGetProcAddress( hMod, _T("MessageBoxA") );	
	TCHAR szText[MAX_PATH] = {0};
	TCHAR szTemp[10] = {0};
	itoa( (DWORD)Fun, szTemp, 16 );
	memcpy( szText, _T("现在MessageBoxA在: "), MAX_PATH );
	_tcscat( szText, szTemp );
	Fun( NULL, szText, _T("成功了"), MB_OK );

	printf("Hello World!\n");
	return 0;
}

上传的附件:
最新回复 (5)
酒色财气
雪    币: 179
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:110 )
在线值:
发帖
18
回帖
140
粉丝
0
酒色财气 活跃值 2 2011-9-27 14:55
2
0
发现在分区块读入内存那里,没有判断那一个是重定位区块。
直接用的最后个区块。大家自己可以改改!
littlewisp
雪    币: 2426
活跃值: 活跃值 (26)
能力值: ( LV10,RANK:170 )
在线值:
发帖
60
回帖
525
粉丝
1
littlewisp 活跃值 2 2011-9-27 15:19
3
0
收藏,以后备用。多谢分享
cxthl
雪    币: 229
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
14
回帖
120
粉丝
0
cxthl 活跃值 2 2011-9-27 15:24
4
0
像reload and run
dongge
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
8
粉丝
0
dongge 活跃值 2011-9-27 18:02
5
0
学习了 多谢分享
miWusn
雪    币: 159
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
35
粉丝
0
miWusn 活跃值 2019-7-22 08:51
6
0
运行无效,OD调试对比发现一条call esi指令里esi是0 上面的 mov esi,[xxxxxx]  内存一看xxxxxx处全0? 是哪里的问题
游客
登录 | 注册 方可回帖
返回