zoukankan      html  css  js  c++  java
  • 2019-2020-2 20174310《网络对抗技术》Exp1+ 逆向进阶

    WINDOWS系统下

    导入表注入原理及简单的代码实现

    一、基础知识

      1.注入的种类:

    • 注册表注入 
    • 导入表注入 (本次实验内容)
    • 特洛伊注入 
    • 远程线程注入 
    • 无DLL注入
    • Apc 注入
    • Windows挂钩注入DLL
    • 输入法注入

      2.导入表注入原理: 

    • 当Exe被加载时,系统会根据Exe导入表信息来加载需要用到的DLL,导入表注入的原理就是修改exe导入表,将自己的DLL添加到exe的导入表中,这样exe运行时可以将自己的DLL加载到exe的进程空间。

      

      3.导入表注入实现步骤:

    • 第一步:
    • 根据目录项(第二个就是导入表)得到导入表信息:
    • typedef struct _IMAGE_DATA_DIRECTORY {
    • DWORD VirtualAddress;
    • DWORD Size;
    • } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
    • VirtualAddress :指向导入表结构
    • Size:导入表的总大小
    • 这两个值都需要
    • 第二步:
    • typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    • union {
    • DWORD Characteristics;
    • DWORD OriginalFirstThunk;
    • };
    • DWORD TimeDateStamp;
    • DWORD ForwarderChain;
    • DWORD Name;
    • DWORD FirstThunk;
    • } IMAGE_IMPORT_DESCRIPTOR;
    • typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
    • 该图片在Excel中完成

     

    • 新增一个导入表需要的空间:
    • A:20字节
    • B:16字节
    • C:取决于DLL名串的长度+1
    • D:取决于函数名的长度+1+2
    • 判断哪一个节的空白区 > Size(原导入表的大小) + 20 + A + B + C + D
    • 如果空间不够:可以将C/D 存储在其他的空白区
    • 也就是,只要空白区 > Size + 0x20就可以了
    • 如果仍然不够,就需要扩大最后一个节,或者新增节来解决.
    • 第三步:
    • 将原导入表全部Copy到空白区
    • 第四步:
    • 在新的导入表后面,追加一个导入表.
    • 第五步:
    • 追加8个字节的INT表 8个字节的IAT表
    • 第六步:
    • 追加一个IMAGE_IMPORT_BY_NAME 结构,前2个字节是0 后面是函数名称字符串
    • 第七步:
    • 将IMAGE_IMPORT_BY_NAME结构的RVA赋值给INT和IAT表中的第一项
    • 第八步:
    • 分配空间存储DLL名称字符串 并将该字符串的RVA赋值给Name属性
    • 第九步:
    • 修正IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size

    二、代码及其注释

    ******************************************************导入表注入的代码(在学习PE过程中写的代码,很多函数在前面的学习中写过,直接复制过来,可能代码看起来,结构设计不是特别好,但是功能是可以实现的)*******************************
    #include "stdafx.h" #include <malloc.h> #include <string.h> typedef struct PE{//pe头中需要用的信息存储在pe结构体中 int e_lfanew; short NumberOfSections; short SizeOfOptionalHeader; int EntryPoint; int ImageBase ; int SectionAlignment ; int SizeOfImage; int FileAlignment; int SizeOfHeaders; }headers; typedef struct sec{// 节表中的一些需要用的信息 int PointerToRawData; int SizeOfRawData; int VirtualAddress; int VirtualSize; }section; typedef struct export{//导入表信息中需要用的信息 char* Name; int Base; int NumberOfFunctions; int NumberOfNames; int AddressOfFunctions; int AddressOfNames; int AddressOfNameOrdinals; char* Name_fun[20]; short ordinal[20]; int RVA[20]; }ex; ex export; headers headers_file; section sections; int flen; char* get_file(){//读入exe,这里用的是一个HTML取色器的简单软件 FILE* fp; char* p; fp = fopen("nMyGetColor.exe","rb"); if(fp == NULL){ printf("file error"); } fseek(fp,0L,SEEK_END); flen = ftell(fp); fseek(fp,0L,SEEK_SET); p = (char*)malloc(flen); fread(p,flen,1,fp); fclose(fp); return p; } char get_char_data(char* start,int distance){//三个辅助函数 char data = *(start+distance); return data; } short get_short_data(char* start,int distance){ short data =*(short*) (start+distance); return data; } int get_int_data(char* start,int distance){ int data =*(int*) (start+distance); return data; } void getInfo(char* start){//获取pe头的重要信息,存储到pe结构体中 headers_file.e_lfanew = get_int_data(start,60); start = start+headers_file.e_lfanew; headers_file.NumberOfSections = get_short_data(start,6); headers_file.SizeOfOptionalHeader = get_short_data(start,20); start = start+24; headers_file.EntryPoint = get_int_data(start,16); headers_file.ImageBase = get_int_data(start,28); headers_file.SectionAlignment = get_int_data(start,32); headers_file.SizeOfImage = get_int_data(start,56); headers_file.FileAlignment = get_int_data(start,36); headers_file.SizeOfHeaders = get_int_data(start,60); } int Rva_to_Foa(int virtualAddress,char* start){//把内存偏移转换为文件偏移 if(virtualAddress<headers_file.SizeOfHeaders){ return virtualAddress; } int fileAddress; int i; char* start_section = start+headers_file.e_lfanew+24+headers_file.SizeOfOptionalHeader; for(i=0;i<headers_file.NumberOfSections;i++){ sections.PointerToRawData = get_int_data(start_section,20); sections.SizeOfRawData = get_int_data(start_section,16); sections.VirtualAddress = get_int_data(start_section,12); sections.VirtualSize = get_int_data(start_section,8); int max; max = sections.VirtualSize>sections.SizeOfRawData?sections.VirtualSize:sections.SizeOfRawData; if(virtualAddress<sections.VirtualAddress+max){ //printf("%d",i); fileAddress = virtualAddress-sections.VirtualAddress+sections.PointerToRawData; /*printf("%x ",sections.VirtualAddress); printf("%x ",sections.PointerToRawData); printf("%x",fileAddress);*/ break; } start_section = start_section+40; } start_section = start+headers_file.e_lfanew+24+headers_file.SizeOfOptionalHeader; for(i=0;i<headers_file.NumberOfSections+1;i++){ sections.PointerToRawData = get_int_data(start_section,20); //printf(" %x ",sections.PointerToRawData); sections.SizeOfRawData = get_int_data(start_section,16); sections.VirtualAddress = get_int_data(start_section,12); //memcpy(start_file+sections.PointerToRawData,start_image+sections.VirtualAddress,sections.SizeOfRawData); start_section = start_section+40; } return fileAddress; } char* memcopy_image(char* start_file){ char* start_image; start_image = (char*)malloc(headers_file.SizeOfImage); memset(start_image,0,headers_file.SizeOfImage); memcpy(start_image,start_file,headers_file.SizeOfHeaders); int i; char* start_section = start_file+headers_file.e_lfanew+24+headers_file.SizeOfOptionalHeader; for(i=0;i<headers_file.NumberOfSections;i++){ sections.PointerToRawData = get_int_data(start_section,20); sections.SizeOfRawData = get_int_data(start_section,16); sections.VirtualAddress = get_int_data(start_section,12); sections.VirtualSize = get_int_data(start_section,8); memcpy(start_image+sections.VirtualAddress,start_file+sections.PointerToRawData,sections.SizeOfRawData); start_section = start_section+40; } return start_image; } char* add_section(char* start_image){ char* start_new_image; if(headers_file.SizeOfHeaders-headers_file.e_lfanew-headers_file.SizeOfOptionalHeader-24-headers_file.NumberOfSections*40<80){ printf("space is not statific"); } else{ printf("space is statific"); start_new_image = (char*)malloc(headers_file.SizeOfImage+headers_file.SectionAlignment); memset(start_new_image,0,headers_file.SizeOfImage+headers_file.SectionAlignment); memcpy(start_new_image,start_image,headers_file.SizeOfImage); *(short*)(start_new_image+headers_file.e_lfanew+6) = headers_file.NumberOfSections+1; *(int*)(start_new_image+headers_file.e_lfanew+80) = headers_file.SizeOfImage+headers_file.SectionAlignment; memcpy(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40,start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24,40); *(char*)(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40) = 'a'; *(int*)(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40+8) = headers_file.SectionAlignment; //sections.VirtualSize = headers_file.SectionAlignment; if(sections.VirtualSize>sections.SizeOfRawData){ *(int*)(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40+12) = sections.VirtualAddress+sections.VirtualSize; } else{ *(int*)(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40+12) = sections.VirtualAddress+sections.SizeOfRawData; } //sections.VirtualAddress = sections.VirtualAddress+sections.VirtualSize; *(int*)(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40+16) = headers_file.FileAlignment; //sections.SizeOfRawData = headers_file.FileAlignment; *(int*)(start_new_image+headers_file.e_lfanew+headers_file.SizeOfOptionalHeader+24+headers_file.NumberOfSections*40+20) = sections.PointerToRawData+sections.SizeOfRawData; if(sections.VirtualSize>sections.SizeOfRawData){ sections.VirtualAddress = sections.VirtualAddress+sections.VirtualSize; } else{ sections.VirtualAddress = sections.VirtualAddress+sections.SizeOfRawData; } sections.PointerToRawData = sections.PointerToRawData+sections.SizeOfRawData; sections.VirtualSize = headers_file.SectionAlignment; sections.SizeOfRawData = headers_file.FileAlignment; } return start_new_image; } char* memcopy_file(char* start_image){ char* start_file; start_file = (char*)malloc(flen+headers_file.SectionAlignment); printf("%x",flen+headers_file.SectionAlignment); memset(start_file,0,flen+headers_file.SectionAlignment); memcpy(start_file,start_image,headers_file.SizeOfHeaders); int i; char* start_section = start_image+headers_file.e_lfanew+24+headers_file.SizeOfOptionalHeader; for(i=0;i<headers_file.NumberOfSections+1;i++){ sections.PointerToRawData = get_int_data(start_section,20); printf(" %x ",sections.PointerToRawData); sections.SizeOfRawData = get_int_data(start_section,16); sections.VirtualAddress = get_int_data(start_section,12); memcpy(start_file+sections.PointerToRawData,start_image+sections.VirtualAddress,sections.SizeOfRawData); start_section = start_section+40; } return start_file; } char* move_import(char* start){//最重要的函数,完成了导入表注入的主要功能,其余函数大多为辅助 int virtualAddress = get_int_data(start,headers_file.e_lfanew+128); int fileAddress = Rva_to_Foa(virtualAddress,start); printf("%x",sections.VirtualAddress); char* export_start; //printf("%x",fileAddress); export_start = start+fileAddress; int num=0; while(1){ int original_thunk = get_int_data(export_start,0); int Name = get_int_data(export_start,12); int first_thunk = get_int_data(export_start,16); if(original_thunk==0&&Name==0&&first_thunk==0){ break; } num++;//统计DLL的数量 export_start = export_start+20; } memcpy(start+sections.PointerToRawData,start+fileAddress,num*20); memcpy(export_start,export_start+num*20,20); *(int*)(start+headers_file.e_lfanew+128) = sections.VirtualAddress; *(int*)(start+headers_file.e_lfanew+132) = *(int*)(start+headers_file.e_lfanew+132)+20; *(int*)(start+sections.PointerToRawData+num*20) = sections.VirtualAddress+(num+2)*20; *(int*)(start+sections.PointerToRawData+num*20+12) = sections.VirtualAddress+(num+2)*20+8; *(int*)(start+sections.PointerToRawData+num*20+16) = sections.VirtualAddress+(num+2)*20+18; *(int*)(start+sections.PointerToRawData+(num+2)*20) = sections.VirtualAddress+(num+2)*20+26; char* name = "test.dll"; memcpy(start+sections.PointerToRawData+(num+2)*20+8,name,strlen(name)+1); *(int*)(start+sections.PointerToRawData+(num+2)*20+18) = sections.VirtualAddress+(num+2)*20+26; char* fun_name = "ExportFunction"; memcpy(start+sections.PointerToRawData+(num+2)*20+28,fun_name,strlen(fun_name)+1);//将原来的导入表通过memcpy到新的节中,并将INT和IAT都转入新的节中,并增加一个新的DLL return start; } void copy_file(char* start_file){ FILE* fp = fopen("20174310srq.exe","wb"); fwrite(start_file,flen+headers_file.SectionAlignment,1,fp); fclose(fp); } int main(int argc, char* argv[]) { char* start = get_file(); getInfo(start); char* start_image = memcopy_image(start); free(start); char* start_new_image = add_section(start_image); free(start_image); char* start_file = memcopy_file(start_new_image); char* move_start = move_import(start_file); copy_file(move_start); free(start_file); return 0; }
    //  : 一个简单的DLL,当往4GB虚拟空间上复制dll时会运行Init()函数,弹出一个简单的提示框,用来检验导入表注入是否成功
    //
    **********************************************************************************************mydll.cpp***********************************************************

    // mydll.cpp: implementation of the mydll class.
    //
    //////////////////////////////////////////////////////////////////////

    
    

    #include "stdafx.h"
    #include "mydll.h"

    
    

    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////

    
    

    void Init(){
    MessageBox(0,"INIT","INIT",MB_OK);
    }
    void Destroy(){
    MessageBox(0,"Destory","Destory",MB_OK);
    }
    void ExportFunction(){
    MessageBox(0,"messagefunction","messagefunction",MB_OK);
    }

    ****************************************************************************test.cpp***********************************************************
    #include "stdafx.h"
    #include "mydll.h"
    
    BOOL APIENTRY DllMain( HANDLE hModule, 
                           DWORD  ul_reason_for_call, 
                           LPVOID lpReserved
                         )
    {
        switch(ul_reason_for_call){
        case DLL_PROCESS_ATTACH:
            Init();
            break;
        case DLL_PROCESS_DETACH:
            Destroy();
            break;
        }
        return TRUE;
    }


    三、结果展示

    • 导入表注入后生成新的可执行文件为20174310srq.exe(test.dll必须放在项目的同目录下,否则找不到dll文件,无法成功注入)
    •  双击运行便会首先出现提示框,然后软件正常运行
    •  现在通过PE工具进行进一步检测
    •                                               这是未进行注入的exe

    •                                                              这是注入后的exe

    • 可以看到成功注入了test.dll,且API函数是 ExportFunction()
    • void ExportFunction(){
      MessageBox(0,"messagefunction","messagefunction",MB_OK);
      }
    • 在代码中可以看到

    四、总结

    • 这是一个非常简单的导入表注入,最近在学习win32的知识,打好逆向的基础知识,才能在以后达到一定程度
  • 相关阅读:
    [IOI1994][USACO1.5]数字三角形 Number Triangles
    和为给定数
    小凯的疑惑
    棋盘
    【2020NOI.AC省选模拟#2】C. 送分题
    【NOI OL #2】涂色游戏
    【NOI OL #3】小结
    【NOI OL #1】最小环
    【NOI OL #1】冒泡排序
    【NOI OL #1】序列
  • 原文地址:https://www.cnblogs.com/srq111/p/12489797.html
Copyright © 2011-2022 走看看