導入表注入


1.主要思路
    新建一個測試用的dll,在dll的入口函數中添加一個在加載階段執行的函數Init();
    給目標程序添加一個新節,將導入表移動到新節中;
        IAT表不能移動,因為程序在調用dll中的函數時,都是call的IAT表的絕對地址;然后在IAT表中找到真實的函數地址;
        如果移動了IAT表,需要修復程序中所有使用了IAT表絕對地址的地方,而這些地方難以確定,加上數量多,代價太大;
    在新節中添加一個新的導入表,引用測試用的dll;
        必須至少導入一個dll中的函數,也就是IAT和INT表中至少插入一項,否則系統會忽略該dll;  
    
    踩坑:  
        新節表的Characteristics屬性應該為:c0000040,否則程序無法運行;
 
2.實現
#include "stdafx.h"
#include "PeTool.h"
#include "string.h"
 
#define SRC "C:\\Users\\Administrator\\Desktop\\TraceMe.exe"
#define DEST "C:\\Users\\Administrator\\Desktop\\TraceMe_new.exe"
 
//新增一個節
DWORD addSec(LPVOID pFileBuffer, LPVOID* pSec){
    //1.定義pe頭結構指針
    PIMAGE_DOS_HEADER dosHeader = NULL;        //dos頭指針
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe頭指針
    PIMAGE_OPTIONAL_HEADER32 opHeader = NULL;    //可選pe頭指針
    PIMAGE_SECTION_HEADER seHeader = NULL;    //節表指針
 
    //2.初始化頭結構指針
    dosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    if(dosHeader->e_magic != IMAGE_DOS_SIGNATURE){
        printf("不是有效MZ標記\n");
        return 0;
    }
    if(*((PDWORD)((DWORD)pFileBuffer + dosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
        printf("不是有效PE標記\n");
        free(pFileBuffer);
        return 0;
    }
    peHeader = (PIMAGE_FILE_HEADER) ((DWORD)pFileBuffer + dosHeader->e_lfanew + 4);
    opHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    seHeader = (PIMAGE_SECTION_HEADER) ((DWORD)opHeader + peHeader->SizeOfOptionalHeader);
 
    //3.新增一個節表
    PIMAGE_SECTION_HEADER newSec = seHeader + peHeader->NumberOfSections;    //新節表的指針
    if(((DWORD)pFileBuffer + opHeader->SizeOfHeaders - (DWORD)newSec) < 80){
        printf("空間不足插入新的節表\n");
        return 0;
    }
 
    //4.設置新節表
    strcpy((char*)newSec->Name, ".Inject");
    newSec->Misc.VirtualSize = 0x1000;                    //新節的內存鏡像大小為1000
    newSec->VirtualAddress = opHeader->SizeOfImage;        //新節的內存偏移為內存鏡像大小
    newSec->SizeOfRawData = 0x1000;                        //新節的文件鏡像大小為1000
    PIMAGE_SECTION_HEADER lastSec = seHeader + (peHeader->NumberOfSections -1);    //最后一個節表
    newSec->PointerToRawData = lastSec->PointerToRawData + lastSec->SizeOfRawData;    //新節的文件偏移緊接最后一個節
    newSec->Characteristics = 0xc0000040;        //導入表所在節的屬性為c0000040,否則程序無法運行
    
    //5.設置全0節表
    memset((LPVOID)(newSec+1), 0, 40);
 
    //6.修頭信息
    peHeader->NumberOfSections = peHeader->NumberOfSections + 1;
    opHeader->SizeOfImage = opHeader->SizeOfImage + 0x1000;
 
    //7.申請內存
    LPVOID sec = malloc(0x1000);
    if(!sec){
        printf("給新節申請內存失敗\n");
        return 0;
    }
    memset(sec, 0, 0x1000);
 
    //8.返回
    *pSec = sec;
    return 0x1000;
}
 
//導入表注入
void dllInject(){
    //定義pe頭結構指針
    PIMAGE_DOS_HEADER dosHeader = NULL;        //dos頭指針
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe頭指針
    PIMAGE_OPTIONAL_HEADER32 opHeader = NULL;    //可選pe頭指針
    PIMAGE_DATA_DIRECTORY dataDir = NULL;        //數據目錄指針
    PIMAGE_IMPORT_DESCRIPTOR importDir= NULL;    //導入表指針;   
 
    //1.將文件讀入內存
    LPVOID pFileBuffer = NULL;
    DWORD fileSize = ReadPEFile(SRC, &pFileBuffer);
    if(!pFileBuffer){
        printf("讀取dll文件失敗\n");
        return;
    }
 
    //2.初始化頭結構指針
    dosHeader = (PIMAGE_DOS_HEADER) pFileBuffer;
    peHeader = (PIMAGE_FILE_HEADER) ((DWORD)pFileBuffer + dosHeader->e_lfanew + 4);
    opHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    dataDir = opHeader ->DataDirectory;
    importDir = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + RvaToFileOffset(pFileBuffer, (dataDir + 1)->VirtualAddress ));
 
    //3.新增一個節
    LPVOID newSec = NULL;
    DWORD secSize = addSec(pFileBuffer, &newSec);
    if(!newSec){
        printf("新增節失敗\n");
        return;
    }
 
    //4.復制導入表
    PIMAGE_IMPORT_DESCRIPTOR copyImport = (PIMAGE_IMPORT_DESCRIPTOR)newSec;
    LPVOID copyDir = newSec;
    int i = 0;
    while((importDir+i) -> OriginalFirstThunk){
        memcpy(copyDir, (LPVOID)(importDir+i), 20);
        copyDir = (LPVOID)((DWORD)copyDir + 20);
        i++;
    }
    (dataDir + 1) -> VirtualAddress = fileSize;    //修復數據目錄
 
    //5.新增一個導入表
    PIMAGE_IMPORT_DESCRIPTOR newImport = (PIMAGE_IMPORT_DESCRIPTOR)copyDir;
 
    //添加IMAGE_IMPORT_BY_NAME
    PIMAGE_IMPORT_BY_NAME newImportName = (PIMAGE_IMPORT_BY_NAME)((DWORD)newImport + 20*2);
    newImportName -> Hint = 1;
    LPSTR newFunName = (LPSTR)((DWORD)newImportName + 2);
    strcpy(newFunName, "ExportFunction");    //將待注入的dll中的導出的函數名設置到這里
 
    //添加INT表
    PDWORD newInt = (PDWORD) ((DWORD)newFunName + strlen(newFunName) + 1);
    *newInt = fileSize + ((DWORD)newImportName - (DWORD)newSec);
    newImport ->OriginalFirstThunk = fileSize + ((DWORD)newInt - (DWORD)newSec);    //修復新導入表   
 
    //添加IAT表
    LPVOID newIat = (LPVOID) ((DWORD)newInt + 8);
    memcpy(newIat, (LPVOID)newInt, 8);
    newImport ->FirstThunk = fileSize + ((DWORD)newIat - (DWORD)newSec);    //修復新導入表  
    
    //添加dll名
    LPSTR newDllName = (LPSTR)((DWORD)newIat + 8);
    strcpy(newDllName, "InjectDll.dll");    //將待注入的dll名設置在這里
    newImport ->Name = fileSize + ((DWORD)newDllName - (DWORD)newSec);    //修復新導入表  
    
    //6.寫出新文件
    FILE* newFile = fopen(DEST, "a+b");
    if(!newFile){
        printf("打開新文件失敗\n");
        free(pFileBuffer);
        free(newSec);
        return;
    }
    size_t m = fwrite(pFileBuffer, fileSize, 1, newFile);
    if(!m){
        printf("寫出文件第一部分失敗\n");
        fclose(newFile);
        free(pFileBuffer);
        free(newSec);
        return;
    }
    //寫出新節
    size_t n = fwrite(newSec, secSize, 1, newFile);
    if(!n){
        printf("寫出文件第二部分失敗\n");
        fclose(newFile);
        free(pFileBuffer);
        free(newSec);
        return;
    }
 
    //關閉文件並返回
    fclose(newFile);
    free(pFileBuffer);
    free(newSec);
    printf("done\n");
    return;
}
 
int main(int argc, char* argv[])
{
    //導入表注入
    dllInject();
    getchar();
}

 

結果:可以看到在程序運行前彈出了窗口;
    說明dll的入后函數被調用;
    也就是dll被成功注入;
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM