看到有人说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;
}
上传的附件 CopySysDll.7z