-
-
[原创]注入静态文件------------修改引入表
-
发表于:
2009-9-18 23:28
7413
-
[原创]注入静态文件------------修改引入表
本文通过对引入表的修改,达到修改引入函数的调用流程。同时也可以在静态修改相关地址后,删除相关导入库,达到隐藏导入函数的目的。
相关工具:RadAsm,OllyICE,WinHex,Stud_PE
1.静态引入库函数的调用方法
CALL XXXX
XXXX:JMP [AAAA] 也可以直接 CALL [AAAA]
不管采用哪种方式,它们都得读取地址AAAA处的数据,如果修改AAAA地址处的数据就可以达到转移函数流程的功能。怎样去查找这个地址呢,这就得熟悉与导入表相关的数据结构。
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk;
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_THUNK_DATA32 {
union {
PBYTE ForwarderString;
PDWORD Function;
DWORD Ordinal;
PIMAGE_IMPORT_BY_NAME AddressOfData;
} u1;
} IMAGE_THUNK_DATA32;
在第一个数据结构中,我们只关心FirstThunk这个数据,它是指向一个IMAGE_THUNK_DATA数组的RVA。在Windows加载可执行文件的过程中,windows会将这个数据替换成相关函数的绝对地址。在没有替换之前,IMAGE_THUNK_DATA数组的每一项是指向相关函数名的RVA(如果函数通过序号引入,就不是这样)。通过定位要替换的函数,然后修改数组内容,就可以达到目的。
2.添加一个段
修改的地址应该指向什么地方呢,当然是我所添加的代码。为了防止添加代码对原文件的影响,这里添加了一个新的段。
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];段名8个字节
union {
DWORD PhysicalAddress;
DWORD VirtualSize;对齐前的长度
} Misc;
DWORD VirtualAddress;段的RVA
DWORD SizeOfRawData;对齐后在磁盘文件的大小
DWORD PointerToRawData;该段在磁盘文件中的偏移
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
上面IMAGE_SECTION_HEADER这个数据结构,加黑体项都是一定要设置的,注意数据对齐,磁盘文件200H,内存文件1000H。设置好新段的数据后,还要修改FileHeader.NumberOfSections以及OptionalHeader.SizeOfImage。特别是SizeOfImage的数值,计算不正确会死的很惨。具体的添加过程看代码吧。
3.函数地址的动态获取和调用
labelstart:
MOV EBX,7C800000H;直接取kernel32.dll的地址 硬编码
;CALL GetAddr,EBX,0AADF0F1H;取LoadLibraryA的地址
PUSH 0AADF0F1H
PUSH EBX
label1: CALL label1;调用自身 将来会被替换 E8 FFFFFFFBH ;label1-labelstart+Sec
;;调用LoadLibraryA("USER32.dll")
PUSH 00006C6CH;0 0 l l
PUSH 642E3233H;d . 2 3
PUSH 52455355H;R E S U
MOV EBX,ESP
PUSH EBX
CALL EAX
ADD ESP,0CH
;;;;;;;;;;;;;
;;GetAddr,EBX,078A5C51H ;MessageBoxA
PUSH 078A5C51H
PUSH EAX
label2: CALL label2 ;E8 FFFFFFFB
JMP EAX;-------》这里就去了MessageBoxA了
NOP
NOP
labelend:
NOP
上面这段代码是要写入新段的,而且在CALL label1和CALL label2这两处的代码在写入文件后是要修改成GetAddr地址的。GetAddr这个函数就是用来获取函数地址的,它也会被写入到新段。
4.代码的写入及函数调用重定位
在实例中,写入了一个函数和一段函数调用代码。代码的写入,最重要的就是计算添加代码的长度,这个只需要在一段代码的收尾添加两个标号就可以了。函数在执行文件中,写入新的执行文件后,如果要调用的话就得重新计算相对偏移地址。
函数相对地址调用:CALL XXXX,XXXX为调用处代码相对于函数的距离。这条指令的长度为5BYTE,相对地址是有正负的,而且调用处指令的长度一定得加上或减去才行。
大家看代码吧,代码写的很乱。不知道这种程序能干什么,哎.............
排版有问题,请看附件中的word文档
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)