PE格式之输入表

紧接着上一篇的千里追踪输入表,现在终于可以开始看输入表里面的神奇东东了。。。

还是copy小甲鱼的课件。。。。

输入表结构

回顾一下,在 PE文件头的 IMAGE_OPTIONAL_HEADER 结构中的 DataDirectory(数据目录表) 的第二个成员就是指向输入表的。而输入表是以一个 IMAGE_IMPORT_DESCRIPTOR(简称IID) 的数组开始。每个被 PE文件链接进来的 DLL文件都分别对应一个 IID数组结构。在这个 IID数组中,并没有指出有多少个项(就是没有明确指明有多少个链接文件),但它最后是以一个全为NULL(0) 的 IID 作为结束的标志。


IMAGE_IMPORT_DESCRIPTOR 结构定义如下:

IMAGE_IMPORT_DESCRIPTOR STRUCT 

    union 

        Characteristics              DWORD   ? 

        OriginalFirstThunk        DWORD   ? 

    ends 

    TimeDateStamp                 DWORD   ? 

    ForwarderChain                 DWORD   ? 

    Name                                  DWORD   ? 

    FirstThunk                          DWORD   ?

IMAGE_IMPORT_DESCRIPTOR ENDS 


成员介绍:

OriginalFirstThunk

它指向first thunk,IMAGE_THUNK_DATA,该 thunk 拥有 Hint 和 Function name 的地址。


TimeDateStamp

该字段可以忽略。如果那里有绑定的话它包含时间/数据戳(time/data stamp)。如果它是0,就没有绑定在被导入的DLL中发生。在最近,它被设置为0xFFFFFFFF以表示绑定发生。


ForwarderChain

一般情况下我们也可以忽略该字段。在老版的绑定中,它引用API的第一个forwarder chain(传递器链表)。它可被设置为0xFFFFFFFF以代表没有forwarder。


Name

它表示DLL 名称的相对虚地址(译注:相对一个用null作为结束符的ASCII字符串的一个RVA,该字符串是该导入DLL文件的名称,如:KERNEL32.DLL)。


FirstThunk

它包含由IMAGE_THUNK_DATA定义的 first thunk数组的虚地址,通过loader用函数虚地址初始化thunk。在Orignal First Thunk缺席下,它指向first thunk:Hints和The Function names的thunks。

这个OriginalFirstThunk 和 FirstThunk明显是亲家,两家伙首先名字就差不多哈。那他们有什么不可告人的秘密呢?来,我们看下面一张图(画的很辛苦,大家仔细看哈):

PE教程,PE视频教程,PE原理,PE头教程
 
我们看到:OriginalFirstThunk 和 FirstThunk 他们都是两个类型为IMAGE_THUNK_DATA 的数组,它是一个指针大小的联合(union)类型。每一个IMAGE_THUNK_DATA 结构定义一个导入函数信息(即指向结构为IMAGE_IMPORT_BY_NAME 的家伙,这家伙稍后再议),然后数组最后以一个内容为0 的 IMAGE_THUNK_DATA 结构作为结束标志。

我们得到 IMAGE_THUNK_DATA 结构的定义如下:
IMAGE_THUNK_DATA STRUC
    union u1
      ForwarderString       DWORD  ?        ; 指向一个转向者字符串的RVA
      Function                   DWORD  ?        ; 被输入的函数的内存地址
      Ordinal                     DWORD  ?        ; 被输入的API 的序数值
      AddressOfData        DWORD  ?        ; 指向 IMAGE_IMPORT_BY_NAME
      ends
IMAGE_THUNK_DATA ENDS

我们可以看出由于是union结构,所以IMAGE_THUNK_DATA 事实上是一个双字大小。该结构在不同时候赋予不同的意义(伟大神奇不得鸟……)。其实union这种数据结构很容易理解:说白了就是当时穷,能省就省,再说白了,就是几兄弟姐妹轮流穿一条裤子去相亲!理解了吧?哈哈~

那我们怎么来区分何时是何意义呢?
规定如下:
当 IMAGE_THUNK_DATA 值的最高位为 1时,表示函数以序号方式输入,这时候低 31位被看作一个函数序号。
当 IMAGE_THUNK_DATA 值的最高位为 0时,表示函数以字符串类型的函数名方式输入,这时双字的值是一个 RVA,指向一个 IMAGE_IMPORT_BY_NAME 结构。(演示请看小甲鱼解密系列视频讲座)

好,那接着我们讨论下指向的这个 IMAGE_IMPORT_BY_NAME 结构。IMAGE_IMPORT_BY_NAME 结构仅仅只有一个字型数据的大小,存有一个输入函数的相关信息结构。其结构如下:
IMAGE_IMPORT_BY_NAME STRUCT
    Hint        WORD    ? 
    Name      BYTE      ?
IMAGE_IMPORT_BY_NAME ENDS
 
结构中的 Hint 字段也表示函数的序号,不过这个字段是可选的,有些编译器总是将它设置为 0,Name 字段定义了导入函数的名称字符串,这是一个以 0 为结尾的字符串。
整个过程看起来有点绕有点烦,别急,后边我们有演示哈。


输入地址表(IAT)


为什么由两个并行的指针数组同时指向 IMAGE_IMPORT_BY_NAME 结构呢?第一个数组(由 OriginalFirstThunk 所指向)是单独的一项,而且不能被改写,我们前边称为 INT。第二个数组(由 FirstThunk 所指向)事实上是由 PE 装载器重写的。

好了,那么 PE 装载器的核心操作时如何的呢?这里就给大家揭秘啦~
PE 装载器首先搜索 OriginalFirstThunk ,找到之后加载程序迭代搜索数组中的每个指针,找到每个 IMAGE_IMPORT_BY_NAME 结构所指向的输入函数的地址,然后加载器用函数真正入口地址来替代由 FirstThunk 数组中的一个入口,因此我们称为输入地址表(IAT)。所以,当我们的 PE 文件装载内存后准备执行时,刚刚的图就会转化为下图:
 
PE教程,PE视频教程,PE原理,PE头教程
 
此时,输入表中其他部分就不重要了,程序依靠 IAT 提供的函数地址就可正常运行。

自己在写的时候遇到了很多问题:
1.输入表一定在.idata区块里面吗?
答:当然不是了。在VC编译器下面是这样的,但是不同的编译器下面是不一样的。而且区块的名称只是名称而已,没有什么大用处。
2.注意一下 IMAGE_THUNK_DATA这个数据结构,可以回上去看看小甲鱼的课件,它是一个联合体类型。


当 IMAGE_THUNK_DATA 值的最高位为 0时,表示函数以字符串类型的函数名方式输入,这时双字的值是一个 RVA,指向一个 
这个时候很好办,我们可以找到这个RVA换算成offset 最终获得它的函数名称

当 IMAGE_THUNK_DATA 值的最高位为 1时,表示函数以序号方式输入,这时候低 31位被看作一个函数序号。
这个时候就讨厌了,如果没有考虑到这个情况的话,程序很可能会因为错误的指针而出错。
这个时候我们就应该用一个if语句来进行一下判断:

PIMAGE_THUNK_DATA SrcImageThunkData = (PIMAGE_THUNK_DATA) PINT;
if ( ! (SrcImageThunkData[i].u1.Ordinal & 0x80000000))

这里用到了 & 按位与运算
注意一下这里的 0x80000000是十六进制的,0x8转换成二进制就是1000 这样最高位就是1了 
通过这个if条件的判断,就可以知道联合体的成员是ForwarderString 还是Ordinal                     
好吧,下面把我自己写的代码贴上来,虽然说有点乱,只是当做自己的笔记。大家可以不看的。因为代码写的很不工整。。。。


#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <winnt.h>

const TCHAR* FileName = L"d:\\PING.exe";
//文件目录
const TCHAR* NewFileName = L"d:\\PING2.exe";
//复制的文件目录
HANDLE hFile;
//文件句柄
BYTE* pBase = NULL;
//基地址
int NumberOfSections;
//区块表的个数
DWORD IMPORT_RVA = NULL;
//输入表的RVA
DWORD IMPORT_OFFSET = NULL;
//输入表的offset
DWORD IN_IMPORT_RVA = NULL;
//输入表所在的区块的起始RVA
DWORD IN_IMPORT_OFFSET = NULL;
//输入表所在区块的物理起始地址
BYTE* fnReadFile();
//读取文件
int fnReadPE (BYTE *pBuffer);
//读取PE文件信息
BYTE* fnReadDosHeader(BYTE* pBuffer);
//读取dos文件头信息
int fnReadNTHeader(BYTE* pBuffer);
//读取 PE文件头信息
int fnReadFileHeader(BYTE* ImageFileHeader);
//读取PE文件头中的FileHeader结构的信息
int fnReadOptionalHeader(BYTE* ImageOptionalHeader);
//读取PE文件头中的OptionalHeader结构的信息
int fnReadSectionHeader(BYTE* ImageSectionHeader);
//读取区块表
int fnReadImportTable(BYTE* ImportTable);
//读取输入表
int fnReadDllName(BYTE* PDllName);
//读取DLL名称
int fnReadINT(BYTE* PINT);
//读取INT
int fnReadFunctionName(BYTE* PFunctionName);
//读取函数名称
//int fnAddSectionTable(LONG offset);
//添加PE区块表
int Copy();
//复制文件,防止文件被破坏

IMAGE_SECTION_HEADER  Own_Section_Header;
/*
Own_Section_Header.Name[Own_Section_Header] = ".carl";
Own_Section_Header.VirtualAddress = 9A010000 ;               // 节区的 RVA 地址
Own_Section_Header.SizeOfRawData =00100000 ;              // 在文件中对齐后的尺寸
Own_Section_Header.PointerToRawData = 00020000;         // 在文件中的偏移量
Own_Section_Header.PointerToRelocations = 00040000;     // 在OBJ文件中使用,重定位的偏移
Own_Section_Header.PointerToLinenumbers = 00000000;   // 行号表的偏移(供调试使用地)
Own_Section_Header.NumberOfRelocations =0000;      // 在OBJ文件中使用,重定位项数目
Own_Section_Header.NumberOfLinenumbers = 0000;    // 行号表中行号的数目
Own_Section_Header.Characteristics = 20000060;              // 节属性如可读,可写,可执行等
*/
int main()
{
	Copy();
	BYTE* pBuffer = fnReadFile();

	fnReadPE (pBuffer);

	return 0;
}

BYTE* fnReadFile()
{
	printf("映射文件...\n");
	hFile = CreateFile(NewFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	//读取文件
	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf("打开文件出错\n");
		return 0;
	}
	DWORD dwFileSize = GetFileSize(hFile, NULL);
	//获得文件大小
	BYTE* pBuffer = new BYTE[dwFileSize];
	//new相当于malloc
	DWORD dwSizeOfRead;

	if(!ReadFile(hFile, pBuffer, dwFileSize, &dwSizeOfRead, NULL))
	{
		printf("读取文件出错\n");
		pBase = NULL;
		return 0;
	}
	pBase = pBuffer;
	return pBase;
	//基地址
}

int fnReadPE(BYTE *pBuffer)
{
	printf("读取PE信息...\n");
	BYTE* pBaseNTHeader = fnReadDosHeader(pBuffer);
	//调用fnReadDosHeader函数获取Dos头信息,并且获得PE文件头的基地址
	if (!pBaseNTHeader)
	{
		return 1;
	}

	if (!fnReadNTHeader(pBaseNTHeader))
		//读取PE文件头信息
	{
		return 1;
	}
	return 0;
}

BYTE* fnReadDosHeader(BYTE* pBuffer)
//读取dos文件头信息
{
	printf("读取DOS文件头...\n");
	PIMAGE_DOS_HEADER SrcImageDosHeader = (PIMAGE_DOS_HEADER)pBuffer;
	if (SrcImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		return 0;
	}
	else
	{
		printf("IMAGE_DOS_HEADER结构\n");
		printf("e_magic   :%04x   DOS可执行文件标记\n",SrcImageDosHeader->e_magic);
		printf("e_cblp    :%04x   Bytes on last page of file\n",SrcImageDosHeader->e_cblp);
		printf("e_cp      :%04x   Page in file\n", SrcImageDosHeader->e_cp);
		printf("e_crlc    :%04x   Relocations\n", SrcImageDosHeader->e_crlc);
		printf("e_cparhdr :%04x   Size of header in paragraphs\n", SrcImageDosHeader->e_cparhdr);
		printf("e_minalloc:%04x   Minimum extra paragraphs needed\n", SrcImageDosHeader->e_minalloc);
		printf("e_maxalloc:%04x   Maximum extra paragraphs needed\n", SrcImageDosHeader->e_maxalloc);
		printf("e_ss      :%04x   Initial (relative) SS value DOS代码的初始化堆栈SS\n", SrcImageDosHeader->e_ss);
		printf("e_sp      :%04x   Initial SP value DOS代码的初始化堆栈指针SP\n", SrcImageDosHeader->e_sp);
		printf("e_csum    :%04x   Checksum\n", SrcImageDosHeader->e_csum);
		printf("e_ip      :%04x   Initial IP value DOS代码的初始化指针入口\n", SrcImageDosHeader->e_ip);
		printf("e_cs      :%04x   Initial (relative) CS value DOS代码的初始堆栈入口\n", SrcImageDosHeader->e_cs);
		printf("e_lfarlc  :%04x   File address of elocation table\n", SrcImageDosHeader->e_lfarlc);
		printf("e_ovno    :%04x   Overlay number\n", SrcImageDosHeader->e_ovno);
		printf("e_res[4]  :%04x, %04x, %04x, %04x   Reserved words\n", SrcImageDosHeader->e_res[0],SrcImageDosHeader->e_res[1],SrcImageDosHeader->e_res[2],SrcImageDosHeader->e_res[3]);
		printf("e_oemid   :%04x   OEM identifier (for e_oeminfo)\n", SrcImageDosHeader->e_oemid);
		printf("e_oeminfo :%04x   OEM information; e_oemid specific\n", SrcImageDosHeader->e_oeminfo);
		printf("e_res2[10]:%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,   Reserved words\n", SrcImageDosHeader->e_res2[0],SrcImageDosHeader->e_res2[1],SrcImageDosHeader->e_res2[2],SrcImageDosHeader->e_res2[3],SrcImageDosHeader->e_res2[4],SrcImageDosHeader->e_res2[5],SrcImageDosHeader->e_res2[6],SrcImageDosHeader->e_res2[7],SrcImageDosHeader->e_res2[8],SrcImageDosHeader->e_res2[9]);
		printf("e_lfanew  :%04x   File address of new exe header 指向PE文件头\n", SrcImageDosHeader->e_lfanew);
	}
	LONG  test = (LONG) (SrcImageDosHeader->e_lfanew);
	//fnAddSectionTable(test);//PE文件头的开始位置

	return (BYTE*) (pBuffer + SrcImageDosHeader->e_lfanew);
}

int fnReadNTHeader(BYTE* pBaseNTBuffer)
{
	printf("读取PE文件头...\n");
	PIMAGE_NT_HEADERS SrcImageNTHeader = (PIMAGE_NT_HEADERS)(pBaseNTBuffer);
	if (SrcImageNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		return 1;
	}
	else
	{
		printf("IMAGE_NT_HEADERS结构\n");
		printf("Signature   :%08x\n", SrcImageNTHeader->Signature);
		fnReadFileHeader((BYTE*)&SrcImageNTHeader->FileHeader);
		//读取FileHeader结构的信息
		fnReadOptionalHeader((BYTE*) &SrcImageNTHeader->OptionalHeader);
		//读取OptionalHeader结构的信息
		 fnReadSectionHeader((BYTE*)IMAGE_FIRST_SECTION(pBaseNTBuffer));
		 //读取区块表
		 fnReadImportTable((BYTE*) (pBase+IMPORT_OFFSET));
	}
	return 0;
}

int fnReadFileHeader(BYTE* ImageFileHeader)
{

	PIMAGE_FILE_HEADER SrcImageFileHeader = (PIMAGE_FILE_HEADER)ImageFileHeader;
	printf("IMAGE_FILE_HEADERS结构\n");
	printf("Machine:              %04x\n",  SrcImageFileHeader->Machine);
	printf("NumberOfSections:     %04x\n",  SrcImageFileHeader->NumberOfSections);
	printf("TimeDateStamp:        %08x\n",  SrcImageFileHeader->TimeDateStamp);
	printf("PointerToSymbolTable: %08x\n",  SrcImageFileHeader->PointerToSymbolTable);
	printf("NumberOfSymbols:      %08x\n",  SrcImageFileHeader->NumberOfSymbols);
	printf("SizeOfOptionalHeader: %04x\n",  SrcImageFileHeader->SizeOfOptionalHeader);
	printf("Characteristics:      %04x\n",  SrcImageFileHeader->Characteristics);
	NumberOfSections = SrcImageFileHeader->NumberOfSections;
	return 0;
}

int fnReadOptionalHeader(BYTE* ImageOptionalHeader)
{
	PIMAGE_OPTIONAL_HEADER SrcImageOptional_Header = (PIMAGE_OPTIONAL_HEADER)ImageOptionalHeader;
	printf("IMAGE_OPTIONAL_HEADER结构\n");

	// Standard fields.
	printf("Magic:                        %04x\n", SrcImageOptional_Header->Magic);
	printf("MajorLinkerVersion:            %02x\n", SrcImageOptional_Header->MajorLinkerVersion);
	printf("MinorLinkerVersion:            %02x\n", SrcImageOptional_Header->MinorLinkerVersion);
	printf("SizeOfCode:                    %08x\n", SrcImageOptional_Header->SizeOfCode);
	printf("SizeOfInitializedData:        %08x\n", SrcImageOptional_Header->SizeOfInitializedData);
	printf("SizeOfUninitializedData:    %08x\n", SrcImageOptional_Header->SizeOfUninitializedData);
	printf("AddressOfEntryPoint:        %08x\n", SrcImageOptional_Header->AddressOfEntryPoint);
	printf("BaseOfCode:                    %08x\n", SrcImageOptional_Header->BaseOfCode);
	printf("BaseOfData:                    %08x\n", SrcImageOptional_Header->BaseOfData);

	// NT additional fields.
	printf("ImageBase:                  %08x\n", SrcImageOptional_Header->ImageBase);
	printf("SectionAlignment:           %08x\n", SrcImageOptional_Header->SectionAlignment);
	printf("FileAlignmen:               %08x\n", SrcImageOptional_Header->FileAlignment);
	printf("MajorOperatingSystemVersion:%04x\n", SrcImageOptional_Header->MajorOperatingSystemVersion);
	printf("MinorOperatingSystemVersion:%04x\n", SrcImageOptional_Header->MinorOperatingSystemVersion);
	printf("MajorImageVersion;          %04x\n", SrcImageOptional_Header->MajorImageVersion);
	printf("MinorImageVersion:          %04x\n", SrcImageOptional_Header->MinorImageVersion);
	printf("MajorSubsystemVersion:      %04x\n", SrcImageOptional_Header->MajorSubsystemVersion);
	printf("MinorSubsystemVersion:      %04x\n", SrcImageOptional_Header->MinorSubsystemVersion);
	printf("Win32VersionValue:          %08x\n", SrcImageOptional_Header->Win32VersionValue);
	printf("SizeOfImage:                %08x\n", SrcImageOptional_Header->SizeOfImage);
	printf("SizeOfHeaders:              %08x\n", SrcImageOptional_Header->SizeOfHeaders);
	printf("CheckSum:                   %08x\n", SrcImageOptional_Header->CheckSum);
	printf("Subsystem:                  %04x\n", SrcImageOptional_Header->Subsystem);
	printf("DllCharacteristics:         %04x\n", SrcImageOptional_Header->DllCharacteristics);
	printf("SizeOfStackReserve:         %08x\n", SrcImageOptional_Header->SizeOfStackReserve);
	printf("SizeOfStackCommit:          %08x\n", SrcImageOptional_Header->SizeOfStackCommit);
	printf("SizeOfHeapReserve:          %08x\n", SrcImageOptional_Header->SizeOfHeapCommit);
	printf("SizeOfHeapCommit:           %08x\n", SrcImageOptional_Header->SizeOfHeapCommit);
	printf("LoaderFlags:                %08x\n", SrcImageOptional_Header->LoaderFlags);
	printf("NumberOfRvaAndSizes:        %08x\n", SrcImageOptional_Header->NumberOfRvaAndSizes);
	//获得数据目录表中输入表的大小和RVA地址
	printf("IMAGE_DIRECTORY_ENTRY_EXPOET Size:   %08x\n", SrcImageOptional_Header->DataDirectory[1].Size);
	printf("IMAGE_DIRECTORY_ENTRY_EXPOET VirtualAddress(RVA):   %08x\n", SrcImageOptional_Header->DataDirectory[1].VirtualAddress);
	IMPORT_RVA = SrcImageOptional_Header->DataDirectory[1].VirtualAddress;
	return 0;
}

int fnReadSectionHeader(BYTE* ImageSectionHeader){
	int i = 0;
	int NUMBER_OF_RVA = NULL;
	//获得输入表所在的区块位置
	PIMAGE_SECTION_HEADER SrcImageSectionHeader = (PIMAGE_SECTION_HEADER) ImageSectionHeader;
	//数组名可以看成是指针,所以下面可以用数组的方式来表示相当于 (i+1) *sizeof(PIMAGE_SECTION_HEADER)
	printf("IMAGE_SECTION_HEADER结构\n");
	for (i = 0; i < NumberOfSections; i++)
	{
		char SectionName[9];
		memset(SectionName, 0, sizeof(SectionName));
		memcpy(SectionName, SrcImageSectionHeader[i].Name, 8);
		printf("name:%s\n", SectionName);
		printf("Misc:                %08x\n", SrcImageSectionHeader[i].Misc);
		printf("VirtualAddres:       %08x\n", SrcImageSectionHeader[i].VirtualAddress);
		printf("SizeOfRawData:       %08x\n", SrcImageSectionHeader[i].SizeOfRawData);
		printf("PointerToRawData:    %08x\n", SrcImageSectionHeader[i].PointerToRawData);
		printf("PointerToRelocations:%08x\n", SrcImageSectionHeader[i].PointerToRelocations);
		printf("PointerToLinenumbers:%08x\n", SrcImageSectionHeader[i].PointerToLinenumbers);
		printf("NumberOfRelocations: %04x\n", SrcImageSectionHeader[i].NumberOfRelocations);
		printf("NumberOfLinenumbers: %04x\n", SrcImageSectionHeader[i].NumberOfLinenumbers);
		printf("Characteristics:     %08x\n", SrcImageSectionHeader[i].Characteristics);
		if (i < NumberOfSections - 1)
		if (IMPORT_RVA >= SrcImageSectionHeader[i].VirtualAddress && IMPORT_RVA < SrcImageSectionHeader[i+1].VirtualAddress)
			NUMBER_OF_RVA = i;
	}
	printf("输入表所在的区块是在第%d个区块\n", NUMBER_OF_RVA+1);
	IMPORT_OFFSET = IMPORT_RVA - (SrcImageSectionHeader[NUMBER_OF_RVA].VirtualAddress - SrcImageSectionHeader[NUMBER_OF_RVA].PointerToRawData);
	
	//printf("%08x\n", SrcImageSectionHeader[NUMBER_OF_RVA].VirtualAddress);
	//printf("%08x\n", SrcImageSectionHeader[NUMBER_OF_RVA].PointerToRawData);

	IN_IMPORT_RVA = SrcImageSectionHeader[NUMBER_OF_RVA].VirtualAddress;
	//输入表所在的区块的起始RVA
	IN_IMPORT_OFFSET = SrcImageSectionHeader[NUMBER_OF_RVA].PointerToRawData;
	//输入表所在区块的物理起始地址

	//printf("输入表的RVA是%08x\n", IMPORT_RVA);
	//printf("输入表的offset是%08x\n", IMPORT_OFFSET);
	return 0;
}

int fnReadImportTable(BYTE* ImportTable)
{
	PIMAGE_IMPORT_DESCRIPTOR SrcImageImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImportTable;
	printf("输入表内容.....\n");
	for (int i = 0; SrcImageImportDescriptor[i].OriginalFirstThunk != 0; i++)
	//IID最后一个结构如果全部为0标志着结束
	{
		printf("OriginalFirstThunk is %08x\n",SrcImageImportDescriptor[i].OriginalFirstThunk);
		printf("TimeDataStamp is %08x\n", SrcImageImportDescriptor[i].TimeDateStamp);
		printf("ForwarderChain is %08x\n",SrcImageImportDescriptor[i].ForwarderChain);
		printf("Name is %08x\n", SrcImageImportDescriptor[i].Name);
		printf("FirstChunk is  %08x\n ",SrcImageImportDescriptor[i].FirstThunk);
		printf("\n");

		fnReadDllName((BYTE*)(SrcImageImportDescriptor[i].Name - IN_IMPORT_RVA + IN_IMPORT_OFFSET + pBase));
		fnReadINT((BYTE*) (SrcImageImportDescriptor[i].OriginalFirstThunk - IN_IMPORT_RVA + IN_IMPORT_OFFSET + pBase) );

		//BYTE * SrcImageThunkData = SrcImageImportDescriptor[i].OriginalFirstThunk;
		//PIMAGE_THUNK_DATA SrcImageThunkData = 

	}
	return 0;
}

int fnReadDllName(BYTE* PDllName)
{
	char* Dll;
	Dll = (char*)PDllName;
	printf("Dll name is %s\n", Dll);
	printf("\n");
	return 0;
}

int fnReadINT(BYTE* PINT)
{
	PIMAGE_THUNK_DATA SrcImageThunkData = (PIMAGE_THUNK_DATA) PINT;
	for (int i = 0; SrcImageThunkData[i].u1.AddressOfData != 0; i++)
	{
		//printf("IMAGE_THUNK_DATA INT  is  %08x\n", SrcImageThunkData[i].u1);

		PIMAGE_IMPORT_BY_NAME SrcImageImportByName = (PIMAGE_IMPORT_BY_NAME)(SrcImageThunkData[i].u1.AddressOfData - IN_IMPORT_RVA + IN_IMPORT_OFFSET + pBase);
		if ( ! (SrcImageThunkData[i].u1.Ordinal & 0x80000000))
																		//这里的8是16进制的,转换为2进制就是1000
		{
			char* FunctionName;
			FunctionName = (char*)(SrcImageImportByName) + sizeof(char) * 2;
			printf("Function name is %s\n", FunctionName);
			printf("\n");			
		}
		/*
		else
		{
			printf("%08x\n",SrcImageThunkData[i].u1.Ordinal & 0x80000000);	
		}
		*/
	}
	
	//fnReadFunctionName((BYTE*) (SrcImageThunkData->u1.AddressOfData - IN_IMPORT_RVA + IN_IMPORT_OFFSET + pBase) );
	return 0;
}
int fnReadFunctionName(BYTE* PFunctionName)
{
	char* FunctionName;
	FunctionName = (char*)PFunctionName;
	printf("Function name is %s\n", FunctionName);
	printf("\n");
	return 0;
}
/*
int fnAddSectionTable(LONG offset)
{
	DWORD dwSizeOfWrite;
	DWORD add = 0x6C726163;
	LPDWORD lpNumberOfBytesWritten = NULL;
	PIMAGE_SECTION_HEADER p = &Own_Section_Header;
	//BYTE* ChangeAddress = ImageSectionTable - 2 *sizeof(BYTE);
	//BYTE* lpWriteBuffer = ImageSectionTable - 8 * sizeof(BYTE);

	//Own_Section_Header.Name[Own_Section_Header] = ".carl";
	//Own_Section_Header.VirtualAddress = 9A010000 ;               // 节区的 RVA 地址
	Own_Section_Header.SizeOfRawData =00100000 ;              // 在文件中对齐后的尺寸
	Own_Section_Header.PointerToRawData = 00020000;         // 在文件中的偏移量
	Own_Section_Header.PointerToRelocations = 00040000;     // 在OBJ文件中使用,重定位的偏移
	Own_Section_Header.PointerToLinenumbers = 00000000;   // 行号表的偏移(供调试使用地)
	Own_Section_Header.NumberOfRelocations =0000;      // 在OBJ文件中使用,重定位项数目
	Own_Section_Header.NumberOfLinenumbers = 0000;    // 行号表中行号的数目
	Own_Section_Header.Characteristics = 20000060;              // 节属性如可读,可写,可执行等
	
	SetFilePointer( hFile,  offset,  NULL,	FILE_BEGIN ); 
	if (WriteFile(hFile,  p,  1 * sizeof(Own_Section_Header), &dwSizeOfWrite, NULL ))
		printf("正确写入文件\n");
	else
		printf("写入文件错误\n");

	return 0;
}
*/

int Copy()
{
	BOOL Flag = TRUE;

	if(CopyFile(FileName, NewFileName, Flag))
		printf("成功复制文件\n");
	else
		printf("复制文件失败\n");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值