修改导入表实现DLL注入

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表示'/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, "[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的注入,否则会提示错误。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值