看到有人说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;
}
[课程]FART 脱壳王!加量不加价!FART作者讲授!