[ create a new paste ] login | about

Link: http://codepad.org/EVyJbRI0    [ raw code | fork ]

C, pasted on Jan 11:
//This code work fine when compiled with `cl.exe /TP`,
//but the address of __invoke__start is wrong under debug mode,
//because at the address,it is actually a JMP instruction,
//not the code of the function

#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <assert.h>
//*************
#define RAW_SECTION_ALIGNMENT 0x200
//*************


//RAW_BASE_CODE and RAW_SIZE_CODE *must*  be
//a multiple of RAW_SECTION_ALIGNMENT which was defined above
//注意,RAW_BASE_CODE不能太小了,以免PE文件头的内容被覆盖
#define RAW_BASE_CODE 0x200
#define RAW_SIZE_CODE 0x200

//RAW_BASE_RDATA and RAW_SIZE_RDATA *must* be
//a multiple of RAW_SECTION_ALIGNMENT which was defined above
#define RAW_BASE_RDATA (RAW_BASE_CODE + RAW_SIZE_CODE)
#define RAW_SIZE_RDATA 0x200



//RVA_BASE_CODE 和 RVA_BASE_RDATA都必须按页边界对齐。
//同时我也把节对齐的值设为了一个页面大小(4096k即0x1000)

//这里我没有把内存中的节对齐大小放在头部的宏定义里,
//因为它只能被设置成页面大小的整数倍,而如果设置多了也不会有什么性能提升
#define RVA_BASE_CODE 0x1000
#define RVA_BASE_RDATA 0x2000


/*
 * 每一个 IMPORT_ENTRY 对应于一个dll文件。
 * 一个 IMPORT_ENTRY 指向一个 IAT 表,
 * 每一个 IAT 表在遇到一个全零的 IAT 项时结束
 */

#define IAT_SIZE (2 * sizeof(DWORD))
#define OFFSET_IAT 0

#define RVA_IAT_ENTRY (RVA_BASE_RDATA + OFFSET_IAT)


/*
 * 每一个 IMPORT_ENTRY 项有0x14个字节, 
 * (也即5个DWORD数据)
 * 以一个全零的 IMPORT_ENTRY 项结尾
 */
#define IMPORT_SIZE (2 * sizeof(IMAGE_IMPORT_DESCRIPTOR)) //这里有2个IMPORT_ENTRY项
#define OFFSET_IMPORT 0x08
#define RVA_IMPORT_ENTRY (OFFSET_IMPORT + RVA_BASE_RDATA)


#define CODE_ENTRY_POINT_OFFSET 0
#define CODE_ENTRY_POINT (RVA_BASE_CODE + CODE_ENTRY_POINT_OFFSET)


#define EXEC_IMAGE_BASE 0x00400000

void __invoke__start()
{
	void (__stdcall *MsgBox)(DWORD,DWORD,DWORD,DWORD);
	MsgBox = (void (__stdcall*)(DWORD,DWORD,DWORD,DWORD))(
				(//这里取IAT偏移为0的那个函数指针
					(void**)(EXEC_IMAGE_BASE + RVA_IAT_ENTRY)
				)[0]
	);
	MsgBox(0,0,0,0);
}
void __invoke__end(){}
void construct_file(FILE *fpExec)
{
	{
		IMAGE_DOS_HEADER *pDos;
		pDos = (IMAGE_DOS_HEADER*)malloc(sizeof(IMAGE_DOS_HEADER));
		memset(pDos,0,sizeof *pDos);
		memcpy(&pDos ->e_magic,"MZ",2);
		pDos ->e_lfanew = sizeof *pDos;
		fwrite(pDos,1,sizeof *pDos,fpExec);
		free(pDos);
	}
	{
		IMAGE_NT_HEADERS *pNtHeader;
		pNtHeader = (IMAGE_NT_HEADERS*)malloc(sizeof(IMAGE_NT_HEADERS));
		memset(pNtHeader,0,sizeof *pNtHeader);
		memcpy(pNtHeader,"PE\0\0",4);
		IMAGE_FILE_HEADER *pFileHeader = &pNtHeader ->FileHeader;
		pFileHeader ->Machine = IMAGE_FILE_MACHINE_I386;
		pFileHeader ->NumberOfSections = 2;
		
		pFileHeader ->SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
		pFileHeader ->Characteristics = 0x010F;
		IMAGE_OPTIONAL_HEADER *pOptionalHeader;
		pOptionalHeader = &pNtHeader ->OptionalHeader;
		
		
		pOptionalHeader ->Magic = 0x010B;
		pOptionalHeader ->MajorLinkerVersion = 5;
		pOptionalHeader ->MinorLinkerVersion = 12;
		pOptionalHeader ->SizeOfCode = RAW_SIZE_CODE;
		pOptionalHeader ->SizeOfInitializedData = RAW_SIZE_RDATA;
		//基地址被设置成0x00400000,于是RVA 0x1000被映射到物理地址0x4001000
		pOptionalHeader ->AddressOfEntryPoint = CODE_ENTRY_POINT;
		pOptionalHeader ->BaseOfCode = RVA_BASE_CODE;
		pOptionalHeader ->BaseOfData = RVA_BASE_RDATA;
		pOptionalHeader ->ImageBase = EXEC_IMAGE_BASE;
		pOptionalHeader ->SectionAlignment = 0x1000;
		pOptionalHeader ->FileAlignment = RAW_SECTION_ALIGNMENT;

		pOptionalHeader ->MajorOperatingSystemVersion = 4;
		pOptionalHeader ->MajorSubsystemVersion = 4;

		//头部可以被认为是一个节,所以3个对齐到SectionAlignment的0x1000加起来就是0x3000
		//如果SectionAlignment的值修改了,此处也需要被修改
		pOptionalHeader ->SizeOfImage = 0x3000; 

		//如果RAW_SECTION_ALIGNMENT被改成大于0x200的值,那么此处也需要被修改
		pOptionalHeader ->SizeOfHeaders = 0x200; //向OptionalHeader ->FileAlignment对齐
		
		
		
		pOptionalHeader ->Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
		
		
		
		pOptionalHeader ->SizeOfStackReserve =	0x100000;
		pOptionalHeader ->SizeOfStackCommit =	0x1000;
		pOptionalHeader ->SizeOfHeapReserve =	0x100000;
		pOptionalHeader ->SizeOfHeapCommit =	0x1000;
		pOptionalHeader ->NumberOfRvaAndSizes =	0x10;

		IMAGE_DATA_DIRECTORY *pDataDirectory = pOptionalHeader ->DataDirectory;
		//导入函数表位于RVA 0x2000,导入地址表位于RVA 0x2008
		//它们都在第二个节中
		//而代码位于第一个节
		pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = RVA_IMPORT_ENTRY;
		//0x2008实际上指向一个IMAGE_IMPORT_DESCRIPTOR
		pDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = IMPORT_SIZE;

		pDataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = RVA_IAT_ENTRY;
		pDataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = IAT_SIZE;
		//.....
		fwrite(pNtHeader,1,sizeof(IMAGE_NT_HEADERS),fpExec);
		free(pNtHeader);
	}
	{
		IMAGE_SECTION_HEADER *pSectionHeaders;
		pSectionHeaders = (IMAGE_SECTION_HEADER*)malloc(2 * sizeof(IMAGE_SECTION_HEADER));
		memset(pSectionHeaders,0,2 * sizeof(IMAGE_SECTION_HEADER));
		strcpy((char*)pSectionHeaders[0].Name,".text");
		pSectionHeaders[0].Misc.VirtualSize =
			(char*)__invoke__end - (char*)__invoke__start;//紧缩的
		pSectionHeaders[0].VirtualAddress = RVA_BASE_CODE;
		pSectionHeaders[0].SizeOfRawData = RAW_SIZE_CODE;
		pSectionHeaders[0].PointerToRawData = RAW_BASE_CODE;
		pSectionHeaders[0].Characteristics =
			IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ;
		strcpy((char*)pSectionHeaders[1].Name,".rdata");
		//没紧缩.rdata节,方便后面修改,例如增加IAT地址
		pSectionHeaders[1] .Misc.VirtualSize = RAW_SIZE_RDATA;
		pSectionHeaders[1] .VirtualAddress = RVA_BASE_RDATA;
		pSectionHeaders[1] .SizeOfRawData = RAW_SIZE_RDATA;
		pSectionHeaders[1] .PointerToRawData = RAW_BASE_RDATA;
		pSectionHeaders[1] .Characteristics =
			IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
		


		fwrite(pSectionHeaders,1,2 * sizeof(IMAGE_SECTION_HEADER),fpExec);
		free(pSectionHeaders);
		while(ftell(fpExec) != RAW_BASE_CODE)fputc(0,fpExec);
	}
	{
		char *code = (char*)malloc(RAW_SIZE_CODE);
		memset(code,0,RAW_SIZE_CODE);
		
		memcpy(code,__invoke__start,RAW_SIZE_CODE);
		
		assert(RAW_SIZE_CODE >= (char*)__invoke__end - (char*)__invoke__start);
		fwrite(code,1,RAW_SIZE_CODE,fpExec);
		free(code);
	}
	{
		char *pRData = (char*)malloc(RAW_SIZE_RDATA);
		memset(pRData,0,RAW_SIZE_RDATA);
		
		assert(OFFSET_IMPORT >= OFFSET_IAT + IAT_SIZE);
		const DWORD offsetThunk = 0x30;
		assert(offsetThunk >= OFFSET_IMPORT + IMPORT_SIZE);
		const DWORD offsetFunctionName = 0x38;
		assert(offsetFunctionName >= offsetThunk + IAT_SIZE);
		const DWORD offsetDllName = 0x46;
		IMAGE_IMPORT_DESCRIPTOR *desc;
		desc = (IMAGE_IMPORT_DESCRIPTOR*)(pRData + OFFSET_IMPORT);
		
		//有2份thunk表,
		//一份实际上是IAT表我放在偏移OFFSET_IAT,
		//另一份位于偏移offsetThunk 
		desc ->OriginalFirstThunk = RVA_BASE_RDATA + offsetThunk;
		IMAGE_THUNK_DATA *thunk;
		thunk = (IMAGE_THUNK_DATA*)(pRData + offsetThunk);
		thunk ->u1.Function = RVA_BASE_RDATA + offsetFunctionName;
		
		//描述符的FirstThunk指向另一份同样的thunk表
		//实际上就是IAT,目标文件在被操作系统执行的时候,
		//IAT表的那些指向IMAGE_IMPORT_BY_NAME的指针被替换成函数指针
		assert(RVA_IAT_ENTRY == RVA_BASE_RDATA + OFFSET_IAT);
		desc ->FirstThunk = (DWORD)RVA_IAT_ENTRY;
		thunk = (IMAGE_THUNK_DATA*)(pRData + OFFSET_IAT);
		thunk ->u1.Function = RVA_BASE_RDATA + offsetFunctionName;
		
		
		IMAGE_IMPORT_BY_NAME *imgFunctionName;
		imgFunctionName = (IMAGE_IMPORT_BY_NAME*)(pRData + offsetFunctionName);
		strcpy((char*)imgFunctionName ->Name,"MessageBoxA");
		//注意,下面的sizeof(imgFunctionName ->Hint),
		//最好不要写成sizeof(IMAGE_IMPORT_BY_NAME),
		//因为那个一字节的Name会因为对齐的需要,
		//实际上使得整个sizeof(IMAGE_IMPORT_BY_NAME)为4字节
		assert(offsetDllName >=
				offsetFunctionName +
				sizeof(imgFunctionName ->Hint) +
				strlen((char*)imgFunctionName ->Name) + 1);
		desc ->Name = RVA_BASE_RDATA + offsetDllName;

		strcpy(pRData + offsetDllName,"user32.dll");
		
		fwrite(pRData,1,RAW_SIZE_RDATA,fpExec);
		free(pRData);


	}
}
int main(int argc, char *argv[])
{
	char file[MAX_PATH];
	strncpy(file,argv[0],MAX_PATH);
	if(!strchr(file,'.'))
	{
		strcat(file,".exe");
	}
	FILE *fp = fopen(file,"rb");
	if(!fp)
	{
		perror("");
		return -1;
	}
	fseek(fp,0,SEEK_END);
	printf("file size %d \n",ftell(fp));
	fclose(fp);
	fp = NULL;
	
	strcat(file,".mod.exe");
	FILE *fpExec = fopen(file,"wb");
	if(!fpExec)
	{
		perror("");
		return -1;
	}
	construct_file(fpExec);
	fclose(fpExec);
	
	return 0;
}


Create a new paste based on this one


Comments: