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\n",sections.VirtualAddress); printf("%x\n",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("\n%x\n",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("\n%x\n",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的知识,打好逆向的基础知识,才能在以后达到一定程度
posted @ 2020-03-13 23:14  20174310隋润起  阅读(208)  评论(0编辑  收藏