xiao183
驱动牛犊
驱动牛犊
  • 注册日期2005-09-18
  • 最后登录2010-04-27
  • 粉丝0
  • 关注0
  • 积分101分
  • 威望14点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
阅读:7648回复:20

关于修改导入表实现DLL注入的问题

楼主#
更多 发布于:2007-03-02 21:24
很早以前就知道有这个修改导入表实现DLL注入的方法和代码,当时由于不涉及这方面的研究,所以没有注意,最近才想到开始研究其中的代码,但其中的关键函数AddImportDll的参数DWORD dwBase,这个dwBase是什么地址啊,我研究了半天也没弄明白,难道是pNTHeader->OptionalHeader.ImageBase不成?但我用赋值给dwBase后,程序根本不能给任何一个程序添加一个dll,所以一直不解,请高手指教!!感激不尽!!!以下就是那个函数

int AddImportDll(HANDLE hFile,DWORD dwBase,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 = 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;
const char szDll[256] = "QQ_main.dll";
const char szFunc[256] = "SoftWareGoIn";
strcpy(Add_Data.szDllName, szDll);
strcpy(Add_Data.szFuncName, szFunc);

//
// +1表示'\0'字符
//
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, "No enough space!\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;
}

//
// 修改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;
}

//
// 从节的末尾添加新的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);
return 0;
}
doskey
论坛版主
论坛版主
  • 注册日期2004-12-08
  • 最后登录2016-04-05
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望302点
  • 贡献值0点
  • 好评度300点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2007-03-03 11:55
注DLL有这么复杂吗?
codez
驱动牛犊
驱动牛犊
  • 注册日期2005-06-20
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望73点
  • 贡献值0点
  • 好评度49点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2007-03-03 19:58
比较喜欢暴力注入方式,Write codes to target process。
被注入的代码自己定位 api,就像病毒,而不是通过 LoadLibrary 加载 dll。

这样子很难被发现
yanxizhen
驱动牛犊
驱动牛犊
  • 注册日期2006-02-21
  • 最后登录2011-08-29
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望32点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-03-05 08:32
dBase应该是程序在内存中的ImageBase吧,忘了
GNiDiA
驱动小牛
驱动小牛
  • 注册日期2006-10-11
  • 最后登录2017-10-09
  • 粉丝0
  • 关注0
  • 积分1002分
  • 威望145点
  • 贡献值0点
  • 好评度124点
  • 原创分0分
  • 专家分0分
  • 社区居民
地下室#
发布于:2007-03-05 09:55
看样子是将被修改的文件读到内存中的基地址
wangjianfeng
驱动小牛
驱动小牛
  • 注册日期2004-05-28
  • 最后登录2013-10-02
  • 粉丝0
  • 关注0
  • 积分1002分
  • 威望263点
  • 贡献值0点
  • 好评度260点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2007-03-05 15:21
这是修改引入表啊. dwbase就是 PE 头在内存中的偏移啊.不过很难有EXE有空间允许插入DLL引入项的.
xiao183
驱动牛犊
驱动牛犊
  • 注册日期2005-09-18
  • 最后登录2010-04-27
  • 粉丝0
  • 关注0
  • 积分101分
  • 威望14点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2007-03-06 12:07
注dll并不复杂,这里只是讨论在exe空间导入表增加一个加载dll的例子,难道没有高手给出正确答案吗?
yanxizhen
驱动牛犊
驱动牛犊
  • 注册日期2006-02-21
  • 最后登录2011-08-29
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望32点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2007-03-07 13:45
引用第6楼xiao1832007-03-06 12:07发表的“”:
注dll并不复杂,这里只是讨论在exe空间导入表增加一个加载dll的例子,难道没有高手给出正确答案吗?


很简单的,以前写过,连带在winlogon里禁用文件保护,模仿黑客之门的功能,代码不知道扔哪里了,我找找,你留个email,如果有,发给你
yanxizhen
驱动牛犊
驱动牛犊
  • 注册日期2006-02-21
  • 最后登录2011-08-29
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望32点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2007-03-07 13:50
P.S. 你上面的代码是不能正常工作的,微软规定pe导入表中dll组最后一个应该为空组.......你的代码少分配了一个空间....
gaga_fucker
驱动牛犊
驱动牛犊
  • 注册日期2006-11-10
  • 最后登录2007-04-16
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2007-03-08 12:42
在LOAD IMAGE的时候在内存中插不是更好
CDrea
驱动牛犊
驱动牛犊
  • 注册日期2004-01-07
  • 最后登录2010-12-02
  • 粉丝0
  • 关注0
  • 积分30分
  • 威望3点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2007-03-12 14:42
lpExeName 是要修改的exe文件名,lpDllName是你的dll文件名


void
OpenPEFile(
    LPSTR lpExeName,
    LPSTR lpDllName
)
{
    HANDLE hFile;
    HANDLE hFileMapping;
    LPVOID lpFileBase;
    PIMAGE_DOS_HEADER    dosHeader;
    PIMAGE_NT_HEADERS    pNTHeader;

    
    char szNewFileName[MAX_PATH];
    sprintf(szNewFileName, "%s", lpExeName);
    strcat(szNewFileName, ".bak");
    if(!CopyFile(lpExeName, szNewFileName, FALSE))
    {
        fprintf(stderr, "CopyFile() failed. --err: %d\n", GetLastError());
        return;
    }
//    printf("lpFileName: %s  lpNewFileName: %s\n", lpFileName, lpNewFileName);

    hFile = CreateFile(szNewFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
                    
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        fprintf(stderr, "CreateFile() failed. --err: %d\n", GetLastError());
        return;
    }

    hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if ( hFileMapping == 0 )
    {
        CloseHandle(hFile);
        printf("Couldn't open file mapping with CreateFileMapping()\n");
        return;
    }

    lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
    if ( lpFileBase == 0 )
    {
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        printf("Couldn't map view of file with MapViewOfFile()\n");
        return;
    }

    dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
    pNTHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew);
    if ( dosHeader->e_magic == IMAGE_DOS_SIGNATURE && pNTHeader->Signature == 0x4550 )
    {
        AddImportDll(hFile, lpDllName, (DWORD)dosHeader, pNTHeader);
    }
    else
        printf("unrecognized file format\n");

    UnmapViewOfFile(lpFileBase);
    CloseHandle(hFileMapping);
    CloseHandle(hFile);
}
xiao183
驱动牛犊
驱动牛犊
  • 注册日期2005-09-18
  • 最后登录2010-04-27
  • 粉丝0
  • 关注0
  • 积分101分
  • 威望14点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2007-03-24 21:37
引用第7楼yanxizhen2007-03-07 13:45发表的“”:


很简单的,以前写过,连带在winlogon里禁用文件保护,模仿黑客之门的功能,代码不知道扔哪里了,我找找,你留个email,如果有,发给你


兄弟,最近出差了,所以一直没看贴,我的邮件地址是zhi-tian@163.com,麻烦你发到我邮件里吧,谢谢了
dfsy0427
驱动牛犊
驱动牛犊
  • 注册日期2007-03-27
  • 最后登录2007-11-14
  • 粉丝0
  • 关注0
  • 积分70分
  • 威望8点
  • 贡献值0点
  • 好评度7点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2007-03-27 16:56
如果方便,请E我一份,找了很久了..非常感谢!!
我的邮件地址:dfsy0418@126.com
qiweixue
驱动小牛
驱动小牛
  • 注册日期2004-07-21
  • 最后登录2011-12-19
  • 粉丝0
  • 关注0
  • 积分1006分
  • 威望274点
  • 贡献值0点
  • 好评度268点
  • 原创分1分
  • 专家分0分
13楼#
发布于:2007-04-05 11:38
硬修改导出表,添加自己的dll中的导出函数.
比直接hook目标模块的IAT,然后转到自己的dll要暴力...

如果目标程序检测自己的导出表发现改变,防止这样注入.然后在自我修复.
elva1
驱动牛犊
驱动牛犊
  • 注册日期2006-03-16
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望34点
  • 贡献值0点
  • 好评度22点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2007-04-29 11:22
yanxizhen大哥,我也要一个,研究很久了,谢谢!
muyang008
驱动牛犊
驱动牛犊
  • 注册日期2005-05-06
  • 最后登录2009-02-14
  • 粉丝0
  • 关注0
  • 积分9分
  • 威望5点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2007-05-10 14:47
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
   PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) {

   // Get the address of the module's import section
   ULONG ulSize;
   PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
        //获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针
      ImageDirectoryEntryToData(hmodCaller, TRUE,
      IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);

   if (pImportDesc == NULL)
      return;  // This module has no import section


   // Find the import descriptor containing references to callee's functions
   // //查找记录,看看有没有我们想要的DLL
   for (; pImportDesc->Name; pImportDesc++) {
      PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
      if (lstrcmpiA(pszModName, pszCalleeModName) == 0)
         break;   // Found
   }

   if (pImportDesc->Name == 0)
      return;  // This module doesn't import any functions from this callee

   // Get caller's import address table (IAT) for the callee's functions
    //寻找我们想要的函数
   PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
      ((PBYTE) hmodCaller + pImportDesc->FirstThunk);

   // Replace current function address with new function address
   ////ppfn记录了与IAT表项相应的函数的地址
   for (; pThunk->u1.Function; pThunk++) {

      // Get the address of the function address
      PROC* ppfn = (PROC*) &pThunk->u1.Function;

      // Is this the function we're looking for?
      BOOL fFound = (*ppfn == pfnCurrent);

      if (!fFound && (*ppfn > sm_pvMaxAppAddr)) {

         // If this is not the function and the address is in a shared DLL,
         // then maybe we're running under a debugger on Windows 98. In this
         // case, this address points to an instruction that may have the
         // correct address.

         PBYTE pbInFunc = (PBYTE) *ppfn;
         if (pbInFunc[0] == cPushOpCode) {
            // We see the PUSH instruction, the real function address follows
            ppfn = (PROC*) &pbInFunc[1];

            // Is this the function we're looking for?
            fFound = (*ppfn == pfnCurrent);
         }
      }

      if (fFound) {
         // The addresses match, change the import section address
          //如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数
         WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
            sizeof(pfnNew), NULL);
         return;  // We did it, get out
      }
   }

   // If we get to here, the function is not in the caller's import section
}
znsoft
管理员
管理员
  • 注册日期2001-03-23
  • 最后登录2023-10-25
  • 粉丝300
  • 关注6
  • 积分910分
  • 威望14796点
  • 贡献值7点
  • 好评度2410点
  • 原创分5分
  • 专家分100分
  • 社区居民
  • 最爱沙发
  • 社区明星
16楼#
发布于:2007-05-15 13:42
这种手法太象病毒了吧?
http://www.zndev.com 免费源码交换网 ----------------------------- 软件创造价值,驱动提供力量! 淡泊以明志,宁静以致远。 ---------------------------------- 勤用搜索,多查资料,先搜再问。
cshzxing
驱动牛犊
驱动牛犊
  • 注册日期2007-04-10
  • 最后登录2008-01-07
  • 粉丝0
  • 关注0
  • 积分40分
  • 威望5点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2007-07-28 11:54
引用第7楼yanxizhen于2007-03-07 13:45发表的  :


很简单的,以前写过,连带在winlogon里禁用文件保护,模仿黑客之门的功能,代码不知道扔哪里了,我找找,你留个email,如果有,发给你


老大,如果方便的话,也给我发一份?
我的email:cshzxing@126.com
谢谢了:)
rain357
驱动牛犊
驱动牛犊
  • 注册日期2007-07-12
  • 最后登录2007-08-30
  • 粉丝0
  • 关注0
  • 积分10分
  • 威望2点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2007-08-15 01:11
引用第7楼yanxizhen于2007-03-07 13:45发表的  :


很简单的,以前写过,连带在winlogon里禁用文件保护,模仿黑客之门的功能,代码不知道扔哪里了,我找找,你留个email,如果有,发给你


偶也想要一份,不知道可不可以?
E-Mail: rain357@gmail.com
谢谢
zistzh
驱动牛犊
驱动牛犊
  • 注册日期2005-07-29
  • 最后登录2011-06-01
  • 粉丝0
  • 关注0
  • 积分12分
  • 威望13点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2007-09-01 22:00
引用第7楼yanxizhen于2007-03-07 13:45发表的  :


很简单的,以前写过,连带在winlogon里禁用文件保护,模仿黑客之门的功能,代码不知道扔哪里了,我找找,你留个email,如果有,发给你


可以给我一份吗,正在学习中,十分感谢
EMAIl: zistzh@163.com
上一页
游客

返回顶部