⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 newcoff.cpp

📁 当前支持 16-bit, 32-bit and 64-bit 的二进制文件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// newcoff.cpp
// Copyright (C) 2009 Willow Schlanger

#include "newcoff.h"
#include "newpdb.h"

#include <iostream>
#include "util.h"

namespace ceres
{

// This caches DLL accesses.
struct coff_state_t
{
	std::string root;			// e.g. MYFILE.EXT
	loaded_target_t *primary;	// target for the root
	std::map<std::string, loaded_target_t> secondary;	// other targets. key is e.g. MYDLL.DLL
	
	// given a filename (e.g. X.DLL), this returns a pointer to the loaded target in
	// question or NULL if it has not yet been loaded.
	loaded_target_t *get_target(std::string filename)
	{
		filename = make_uppercase(filename);
		if(filename == root)
			return primary;
		std::map<std::string, loaded_target_t>::iterator i = secondary.find(filename);
		if(i != secondary.end())
			return &i->second;
		return NULL;
	}
};

//--- begin coff
struct PACKED(dos_header_t)
{
	U1 signature[2];	// {'M','Z'} or {'Z','M'}
	U2 size_mod_512;
	U2 size_div_512;	// includes any partial last page
	U2 num_relocs;
	U2 header_size;		// in paragraphs (1 paragraph = 16 bytes)
	U2 min_mem;			// in paragraphs
	U2 max_mem;			// in paragraphs
	U2 initial_ss;		// relative to start of executable
	U2 initial_sp;
	U2 checksum;
	U2 initial_ip;
	U2 initial_cs;		// relative to start of executable
	U2 reloc_offset;	// within header. >= 0x40 for new executables.
	U2 overlay_num;		// normally 0 = main program
	// New executables: 
	U4 unknown;			// ???
	U2 behavior;		// ?
	U1 behavior_reserved[26];	// reserved for additional behavior info
	U4 new_header_offset;	// within disk file
};

enum
{
	it_pe32,
	it_coff32
};

struct loaded_image_t
{
	U4 image_type;			// it_*
	U1 *file_image;			// NULL
	U4 file_image_size;		// zero
	U1 *image;
	U4 image_size;
};

struct PACKED(coff_data_dir_t)
{
	U4 rva;							// rva = address of the table, when loaded, relative to the base of the image
	U4 size;						// size in bytes
};

struct PACKED(coff_t)
{
	U2 machine;						// 0x14c = i386+
	U2 number_of_sections;
	U4 time_date_stamp;
	U4 pointer_to_symbol_table;		// file offset
	U4 number_of_symbols;
	U2 size_of_optional_header;
	U2 characteristics;
	
	U2 magic;						// 0x10b (PE32) or 0x20b (PE32+)
	U1 linker_version_major;
	U1 linker_version_minor;
	U4 code_size;					// total size of all text sections
	U4 initialized_data_size;		// total size of all data sections
	U4 uninitialized_data_size;		// total size of all bss sections
	U4 entrypoint_address;			// rel. to image base when executable is loaded into memory
	U4 base_of_code;				// rel. to image base when loaded into memory; beginning of code section
	U4 base_of_data;				// (absent in PE32+); beginning of data section

	U4 image_base;					// must be a multiple of 64kb. preferred address of 1st byte of image when loaded into memory.
	U4 section_alignment;			// >= file_alignment. typically 4096. sections are aligned to this when loaded into memory.
	U4 file_alignment;				// sections in the file are aligned to this many bytes. typically 512.
	U2 major_os_version;
	U2 minor_os_version;
	U2 major_image_version;
	U2 minor_image_version;
	U2 major_subsystem_version;
	U2 minor_subsystem_version;
	U4 reserved1;					// win32_version_value
	U4 size_of_image;				// size of image in bytes, including all headers. a multiple of section_alignment.
	U4 size_of_headers;				// DOS stub, PE header, and section headers rounded up to a multiple of file alignment
	U4 check_sum;
	U2 subsystem;					// 2=gui, 3=console
	U2 dll_characteristics;
	U4 stack_reserve;
	U4 stack_commit;
	U4 heap_reserve;
	U4 heap_commit;
	U4 loader_flags;				// obsolete
	U4 number_data_dirs;			// typically 16

	coff_data_dir_t data_dirs[1];	// variable size
};

/*
data_dirs[0] = export table
data_dirs[1] = import table
data_dirs[2] = resource table
data_dirs[3] = exception table
data_dirs[4] = certificate table. RVA is really a file pointer.
data_dirs[5] = base relocation table
data_dirs[6] = debug data
data_dirs[7] = architecture-specific data
data_dirs[8] = size is 0. RVA of value to be stored in global pointer register.
data_dirs[9] = thread-local storage (TLS) table
data_dirs[10] = load configuration table
data_dirs[11] = bound import table
data_dirs[12] = import address table (IAT)
data_dirs[13] = delay import descriptor
data_dirs[14] = COM+ runtime header
data_dirs[15] = reserved
*/

struct PACKED(coff_section_header_t)
{
	char name[8];					// 8-byte, null-padded, ascii string. no terminating null if length is exactly 8 bytes.
	U4 virtual_size;				// (or physical address). total size of section when loaded in memory. if > size of raw data, is 0 padded.
	U4 virtual_address;				// address of 1st byte of section, when loaded in memory, relative to image base.
	
	// Note. raw_data_size is the size on disk. it's rounded up to a multiple of file alignment.
	// So, if the actual data size is 513 bytes but file alignment is 512, this will be 1024. But virtual_size will still be 513!
	U4 raw_data_size;				// size of initialized data on disk. must be a multiple of file alignment.
	
	U4 raw_data_pointer;			// file pointer to raw data. 0 if section contains only uninitialized data.
	U4 relocation_pointer;			// zero
	U4 linenum_pointer;				// file pointer to line number entries for section, or zero if none.
	U2 num_relocations;				// zero
	U2 num_linenum_entries;
	
	// 0x00000020 - contains executable code
	// 0x00000040 - contains initialized data
	// 0x00000080 - contains uninitialized data
	// 0x20000000 - executable
	// 0x40000000 - readable
	// 0x80000000 - writable
	U4 characteristics;
};

// The IAT is an array of revc_iat's, terminated by a null one.
// This is really an import directory table, not an import address table. :)
struct PACKED(iat_t)
{
	// import_lookup_table: mask by 0x7fffffff. If bit 31 was 1,
	// import by ordinal. The ordinal is the value &'d by 0x7fffffff.
	// else, import by hint/name. rva of image hint/name, with this
	// format:
	//    U2 hint;
	//    char asciiz_name[<variable size>].
	//    [another null is appended to pad to an even address]
	U4 import_lookup_table_rva;		// U4's, terminated by 0.
	U4 time_date_stamp;
	U4 forwarder_chain;
	U4 name_rva;				// asciiz e.g. "kernel32.dll"
	U4 iat_rva;				// thunk table (these are overwritten)
};

struct PACKED(edt_t)
{
	U4 characteristics;
	U4 time_date_stamp;
	U2 major_version;
	U2 minor_version;
	U4 real_name_rva;
	U4 ordinals_base;			// e.g. 1, if ordinal 1 is at index 0
	U4 number_of_functions;
	U4 number_of_names;
	U4 rva_functions;
	U4 rva_names;
	U4 rva_ordinals;
};

// if a loaded_image_t struct is of type it_pe32, use this function
// on its 'file_image' or 'image' element to get the offset where
// the COFF header starts. Returns 0 on error.
U4 get_coff32(U1 *image, U4 image_size)
{
	if(image_size < 0x1c)
		return 0;
	dos_header_t *dos = (dos_header_t *)image;
	if(dos->signature[0] != 'M' || dos->signature[1] != 'Z')
		if(dos->signature[0] != 'Z' || dos->signature[1] != 'M')
			return 0;
	U4 exe_size = dos->size_div_512 * 512 + dos->size_mod_512;
	if(dos->size_mod_512 != 0)
		exe_size -= 512;
	U4 hdr_size = dos->header_size * 16;
	if(hdr_size > image_size || hdr_size > exe_size)
		return 0;
	if(hdr_size < 0x40)
		return 0;
	U4 new_offset = dos->new_header_offset;
	if(new_offset + 4 > image_size)
		return 0;
	if(image[new_offset] != 'P' || image[new_offset+1] != 'E' ||
		image[new_offset+2] != '\0' || image[new_offset+3] != '\0'
	)
		return 0;
	return new_offset + 4;
}

bool load_image(loaded_image_t &image)
{
	U4 coff_offset = 0;
	if(image.image_type == it_coff32)
		;
	else
	if(image.image_type == it_pe32)
	{
		coff_offset = get_coff32(image.file_image, image.file_image_size);
		if(coff_offset == 0)
			return false;
	}
	U4 coff_size = image.file_image_size - coff_offset;
	
	if(coff_size < sizeof(coff_t) - sizeof(coff_data_dir_t))
		return false;
	coff_t *coff = (coff_t *)(image.file_image + coff_offset);
	if(coff->machine != 0x14c || coff->magic != 0x10b)
		return false;
	
	// is valid - now do the load!
	image.image_size = coff->size_of_image;
	image.image = new U1 [image.image_size];
	for(U4 i = 0; i < image.image_size; ++i)
		image.image[i] = 0;
	
	// Copy header - including DOS stub
	for(U4 i = 0; i < coff->size_of_headers; ++i)
		image.image[i] = image.file_image[i];
	
	coff_section_header_t *sections = (coff_section_header_t *)(image.file_image +
		coff_offset + sizeof(coff_t) - sizeof(coff_data_dir_t) +
		sizeof(coff_data_dir_t) * coff->number_data_dirs
	);
	for(U4 i = 0; i < coff->number_of_sections; ++i)
	{
		if(sections[i].raw_data_pointer == 0)
			continue;
		U4 copy_size = (sections[i].raw_data_size < sections[i].virtual_size) ?
			copy_size = sections[i].raw_data_size :
			copy_size = sections[i].virtual_size
		;
		U1 *src = image.file_image + sections[i].raw_data_pointer;
		U1 *dest = image.image + sections[i].virtual_address;
		for(U4 x = 0; x < copy_size; ++x)
			dest[x] = src[x];
	}
	
	return true;
}
//--- end coff

U1 *do_load_coff(std::string path, std::string file, U8 &size)
{
	U8 raw_size;
	int status = 0;
	size = 0;
	U1 *raw = load_file((path + file).c_str(), size, status);
	if(status != 0)
	{
		raw = load_file(file.c_str(), size, status);
		if(status != 0)
		{
			return NULL;
		}
	}
	loaded_image_t image;
	image.file_image = raw;
	image.image_type = it_coff32;
	image.file_image_size = size;
	bool ok;
	ok = load_image(image);
	if(!ok)
	{
		image.image_type = it_pe32;
		ok = load_image(image);
		if(!ok)
		{
			delete [] raw;
			return NULL;
		}
	}
	delete [] raw;
	image.file_image = NULL;
	size = (U8)(U4)(image.image_size);
	return image.image;
}

U1 *load_target(std::string path, std::string file, loaded_target_t &target)
{
	U8 size = 0;
	target.clear();
	
	U1 *bin = do_load_coff(path, file, size);
	if(bin == NULL)
	{
		return NULL;
	}
	
	coff_t *coff = (coff_t *)(bin + get_coff32(bin, size));
	if(coff == NULL)
	{
		delete [] bin;
		return NULL;
	}

	target.size = size;
	target.base = coff->image_base;
	target.start = coff->entrypoint_address;
	target.module = remove_extension(make_uppercase(file));
	
	return bin;
}

std::string resolve_symbol(dll_finder_t &finder, std::string dll_name, int ordinal, coff_state_t &s);
std::string resolve_symbol(dll_finder_t &finder, std::string dll_name, std::string procedure, coff_state_t &s);

std::string do_resolve_symbol(dll_finder_t &finder, std::string dll_name, std::string procedure, coff_state_t &s)
{
	if(dll_name.empty())
		return "";
	if(dll_name[0] == '#')
	{
		std::string num = std::string(++dll_name.begin(), dll_name.end());
		int i = string_to_unsigned(num);
		if(i == -1)
			return "";
		return resolve_symbol(finder, dll_name, i, s);
	}
	return resolve_symbol(finder, dll_name, procedure, s);
}

loaded_target_t *load_dll(coff_state_t &s, dll_finder_t &finder, std::string dll_name)
{
	loaded_target_t *ptarget = s.get_target(dll_name);

	if(ptarget == NULL)
	{
		std::cerr << ".";
	
		// DLL not already loaded!
		std::string fullname = finder.find(dll_name);
		if(fullname.empty())
		{
			return NULL;
		}
		std::string path, file;
		split_filename(fullname, path, file);
		if(file.empty())
		{
			return NULL;
		}
		
		std::string module = make_uppercase(dll_name);
		ptarget = &s.secondary[module];
		ptarget->clear();
		U1 *bin = load_target(path, file, *ptarget);
		if(bin == NULL)
		{
			return NULL;
		}
		
		// OK, we just loaded a new DLL.
		loaded_target_t &target = *ptarget;
		coff_t *coff = (coff_t *)(bin + get_coff32(bin, target.size));
		if(coff == NULL)
		{
			delete [] bin;
			return NULL;
		}
		
		//--- process exports ---
		if(coff->number_data_dirs == 0 || coff->data_dirs[0].rva == 0 || coff->data_dirs[0].size == 0)
			;	// no exports
		else
		{
			std::map<U4, std::string> xexports;
			edt_t *exports = (edt_t *)(bin + coff->data_dirs[0].rva);
			U4 *functions = (U4 *)(bin + exports->rva_functions);
			U4 *names = (U4 *)(bin + exports->rva_names);
			U2 *ordinals = (U2 *)(bin + exports->rva_ordinals);
	
			for(U4 x = 0; x < exports->number_of_functions; ++x)
			{
				U4 y = x + exports->ordinals_base;
				xexports[y] = std::string("#") + int_to_string(y);
			}
			for(U4 x = 0; x < exports->number_of_names; ++x)
			{
				xexports[ordinals[x] + exports->ordinals_base] = std::string((char *)(bin + names[x]));
			}
			
			using namespace std;
			//cout << "Exports:" << endl;
			std::string newname;
			for(std::map<U4, std::string>::iterator i = xexports.begin(); i != xexports.end(); ++i)
			{
				U8 offset = functions[i->first - exports->ordinals_base];
				
				// note--offset may be 0 at this point. ignore that case.
	
				// check for forwarders.
				if(offset >= coff->data_dirs[0].rva && offset < coff->data_dirs[0].rva + coff->data_dirs[0].size)
				{
					// is a forwarder. we trust no DLL will forward in a cycle, e.g. a.dll -> b.dll -> a.dll.
					// we only check that the target of the forward is NOT THE ROOT (because that would be a
					// cycle and also, if the root forwards it, we won't know since we don't process forwarded
					// exports from the root).
					std::string t = std::string((const char *)(&bin[offset]));
					
					std::string::iterator ix = t.begin();
					while(ix != t.end())
					{
						if(*ix == '.')
							break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -