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

📄 qadasm.cpp

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

#include <fstream>
#include <cstring>
#include <iostream>
#include <string>
#include "newcoff.h"
#include "util.h"
#include "scan.h"

namespace ceres
{

// pre: meta has been zero'd
// post: icode[] is loaded and meta[]'s length and named bitfields are valid.
void do_decode(x86s::icode_t *icode, meta_t *meta, U1 *bin, loaded_target_t &target)
{
	using namespace x86s;
	U8 size = target.size;
	U8 next = size / 10;
	decode_state_t s;
	U8 bytesleft;
	int status;
	for(U8 u = 0; u < size; ++u)
	{
		if(u == next)
		{
			std::cerr << ".";
			next += size / 10;
		}
		
		s.dsz = argsize_32;
		s.insn = bin + u;
		s.icode = icode + u;
		bytesleft = size - u;
		if(bytesleft > 15)
			bytesleft = 15;
		s.end = s.insn + bytesleft;
		status = decode(s);
		
		meta[u].length = 0;
		if(status == 0)
		{
			meta[u].length = s.size;
		}
	}
	
	for(std::map<U8, name_t>::iterator i = target.names.begin(); i != target.names.end(); ++i)
	{
//std::cerr << std::hex << i->first + target.base << " - " << i->second.user_name << std::dec << std::endl;
		meta[i->first].named = 1;
	}
}

}	// namespace ceres

#ifdef _WIN32
#include <windows.h>
std::string system_dir()
{
	char s[16384];
	s[0] = '\0';
	if(GetSystemDirectory(s, 16384) == 0)
		s[0] = '\0';
	return ceres::fixslash(s);
}
#else
std::string system_dir()
{
	return "";
}
#endif

using namespace ceres;

// This prints the name of the given offset to the given stream.
// MSVC sometimes generates debugging symbols at the TARGET of a jump from a procedure.
// We have to deal with that case.
bool out_name(std::ostream &os, U8 offset, scan_target_t &starget, scanprocs_t &sprocs, bool jumps, std::string prefix)
{
	module_t adaptor(starget);
	std::string s;
	if(adaptor.is_special(offset))
		s = adaptor.get_name(offset);
	if(jumps && s.empty())
	{
		if(starget.icode[offset].insn == insn_jmp)
		{
			x86s::icode_t *icode = &starget.icode[offset];
			U8 x;
			x = (U8)icode->imm + (U8)offset + (U8)starget.meta[offset].length + (U8)starget.target->base;
			x &= (U8)(U4)0xffffffff;
			if(x >= starget.target->base)
			{
				x -= starget.target->base;
				if(offset < starget.target->size)
				{
					if(adaptor.is_special(x))
						s = adaptor.get_name(x);
				}
			}
		}
	}
	if(s.empty())
		os << prefix << "_" << std::hex << (offset + starget.target->base) << std::dec;
	else
		os << s;
	return !s.empty();
}

void disassemble(std::ostream &out1, decode_state_t &s, icode_t &newicode, U8 offset, scan_target_t &starget, scanprocs_t &sprocs)
{
	int status;
	char line[1024];
	NasmWriter nasmdis;
	const char *imm;
	const char *dispx;
	char immbuf[1024];
	char dispbuf[1024];

	s.icode = &newicode;
	s.dsz = argsize_32;
	s.insn = starget.bin + offset;
	s.end = s.insn + 15;
	
	status = decode(s);
	
	assert(status == 0);
	
	imm = NULL;
	dispx = NULL;
	
	//---
	U8 target;
	module_t adaptor(starget);
	bool star = false;

	if(s.icode->has_disp && !s.icode->ea.disp8)
	{
		U8 disp = (U8)(U4)s.icode->disp;
		//o << "<d> " << std::hex << disp << std::dec;
		if(disp >= starget.target->base)
		{
			disp -= starget.target->base;
			//o << "<d> " << std::hex << disp << std::dec;
			if(disp < starget.target->size)
			{
				//o << "<a> ";
				if(starget.meta[disp].named)
				{
					std::string s = adaptor.get_name(disp);
					//o << "<b> [" << s << "]";
					if(!s.empty())
					{
						std::strcpy(dispbuf, s.c_str());
						dispx = dispbuf;
					}
				}
			}
		}
	}
	
	switch(encodings[s.encoding].insn)
	{
		case insn__jmpi:
		case insn__calli:
			star = true;
			break;
		case insn_jmp:
		case insn__jcc:
		case insn__jrcxz:
		case insn__loopnz:
		case insn__loopz:
		case insn__loop:
		case insn_call:
			//o << "<ack> ";
			target = (U8)s.icode->imm + offset + (U8)s.size + (U8)starget.target->base;
			target &= (U8)(U4)0xffffffff;
			if(target < starget.target->base)
				break;
			target -= starget.target->base;
			if(target >= starget.target->size)
				break;
			std::string s = "";
			if(starget.meta[target].named)
				s = adaptor.get_name(target);

			if(!s.empty())
			{
				std::strcpy(immbuf, s.c_str());
				imm = immbuf;
			}
			else
			{
				if(sprocs.procs.find(target) == sprocs.procs.end())
				{
					std::sprintf(immbuf, "loc_%x", target + starget.target->base);
					imm = immbuf;
				}
				else
				{
					std::sprintf(immbuf, "fn_%x", target + starget.target->base);
					imm = immbuf;
				}
			}
			break;
	}

	//---
	
	line[0] = '\0';
	nasmdis.disasm(line, &s, imm, dispx, offset + (U8)starget.meta[offset].length + starget.target->base);
	
	out1 << "  " << line << std::endl;
}

void qadasm(std::string filename, scan_target_t &starget, scanprocs_t &sprocs)
{
	using namespace std;
	
	std::cerr << "writing out1.asm...";
	
	ofstream out1("out1.asm");
	out1 << "; out1.asm" << std::endl;
	out1 << "; Diassembly of " << filename << " (decompilable procedures)" << std::endl;
	out1 << std::endl;
	out1 << "; Entrypoint name: ";
	out_name(out1, starget.target->start, starget, sprocs, true, "fn");
	out1 << std::endl;

	x86s::icode_t newicode;
	x86s::decode_state_t s;
	U8 offset;

	for(std::map<U8, scanproc_t>::iterator i = sprocs.procs.begin(); i != sprocs.procs.end(); ++i)
	{
		if(i->second.u.s.no_decompile)
			continue;
		
		out1 << std::endl;
		out1 << "; --- procedure at " << std::hex << (i->first + starget.target->base) << " ---" << std::endl;
		out1 << std::endl;
		out1 << "; consists of " << i->second.blocks.size() << " basic blocks." << std::endl;
		if(i->second.return_depth != -1 && !i->second.return_many)
			out1 << "; return depth: " << i->second.return_depth << " bytes" << std::endl;
		if(i->second.return_many)
			out1 << "; inconsistent return depth" << std::endl;
		if(!i->second.calls.empty() || !i->second.imports.empty() || !i->second.fixed_indirects.empty())
			out1 << "; This procedure calls/invokes:" << std::endl;
		for(std::set<U8>::iterator j = i->second.calls.begin(); j != i->second.calls.end(); ++j)
		{
			out1 << "; - ";
			out_name(out1, *j, starget, sprocs, true, "fn");
			out1 << " (direct)" << std::endl;
		}
		for(std::set<U8>::iterator j = i->second.fixed_indirects.begin(); j != i->second.fixed_indirects.end(); ++j)
		{
			out1 << "; - ";
			out_name(out1, *j, starget, sprocs, true, "fn");
			out1 << " (speculative indirect)" << std::endl;
		}
		for(std::set<std::string>::iterator j = i->second.imports.begin(); j != i->second.imports.end(); ++j)
		{
			out1 << "; - " << *j << " (import)" << std::endl;
		}
		//out_name(out1, i->first, starget, sprocs, true, "fn");
		//out1 << ":" << std::endl;
		
		for(std::map<U8, scanbb_t>::iterator j = i->second.blocks.begin(); j != i->second.blocks.end(); ++j)
		{
			offset = j->first;
			
			out1 << std::endl;
			if(out_name(out1, offset, starget, sprocs, false, ((j->first == i->first) ? "fn" : "loc")))
			{
				out1 << ":  ; " << ((j->first == i->first) ? "fn_" : "loc_") << std::hex << (offset + starget.target->base) << std::dec << std::endl;
			}
			else
			{
				out1 << ":" << std::endl;
			}
						
			for(;;)
			{
				disassemble(out1, s, newicode, offset, starget, sprocs);

				if(offset == j->second.stop)
					break;
				offset += starget.meta[offset].length;
			}
		}
	}

	std::cerr << " done" << std::endl;
	std::cerr << "writing out2.asm...";
	
	ofstream out2("out2.asm");

	out2 << "; out1.asm" << std::endl;
	out2 << "; Diassembly of " << filename << " (undecompilable procedures)" << std::endl;
	out2 << std::endl;
	out2 << "; Entrypoint name: ";
	out_name(out2, starget.target->start, starget, sprocs, true, "fn");
	out2 << std::endl;
	out2 << std::endl;
	
	bool nolabel = false;
	bool start = true;
	
	for(U8 u = 0; u < starget.target->size; )
	{
		while(starget.meta[u].length == 0)
		{
			++u;
			if(u == starget.target->size)
				break;
		}
		if(u == starget.target->size)
			break;

		if(starget.meta[u].procedure == 1)
		{
			if(starget.meta[u].branch == 1)
			{
				out2 << std::endl;
				if(out_name(out2, u, starget, sprocs, false, ((sprocs.procs.find(u) != sprocs.procs.end()) ? "fn" : "loc")))
				{
					out2 << ":  ; " << ((sprocs.procs.find(u) != sprocs.procs.end()) ? "fn_" : "loc_") << std::hex << (u + starget.target->base) << std::dec << std::endl;
				}
				else
				{
					out2 << ":" << std::endl;
				}
			}
			else
			if(!nolabel || start)
			{
				start = false;
				out2 << std::endl;
				out2 << "; ";
				if(out_name(out2, u, starget, sprocs, false, ((sprocs.procs.find(u) != sprocs.procs.end()) ? "fn" : "loc")))
				{
					out2 << " (" << ((sprocs.procs.find(u) != sprocs.procs.end()) ? "fn_" : "loc_") << std::hex << (u + starget.target->base) << std::dec << ")" << std::endl;
				}
				else
				{
					out2 << std::endl;
				}
			}
			disassemble(out2, s, newicode, u, starget, sprocs);
		}
		u += starget.meta[u].length;
		
		nolabel = false;
		if(starget.meta[u].length != 0 && starget.meta[u].procedure != 0)
			nolabel = true;
	}

	std::cerr << " done" << std::endl;
}

int main(int argc, char **argv)
{
	std::cerr << "QADASM 2.0  Copyright (C) 2009 Willow Schlanger" << std::endl;
	std::cerr << "Win32 PE/COFF disassembler (using crudasm engine)" << std::endl;
	std::cerr << std::endl;

	if(argc != 2 && argc != 3 && argc != 4)
	{
		std::cerr << "Usage:    qadasm program.ext [searchpaths] [debugpath]" << std::endl;
		std::cerr << "Examples: qadasm test.exe" << std::endl;
		std::cerr << "          qadasm test.exe c:/windows;c:/windows/system32 c:/symbols" << std::endl;
		return 1;
	}
	
	std::string sysdir = system_dir();
	std::string search;
	if(argc >= 3)
		search = argv[2];
	else
		search = sysdir;
	
	std::string dbgdir = sysdir + "symbols";
	if(argc >= 4)
	{
		dbgdir = argv[3];
	}

	dll_finder_t finder(search);
	std::string s = argv[1];
	std::cerr << make_lowercase(s) << "...";

	loaded_target_t target;
	U1 *bin = NULL;
	load_target(finder, s, target, &bin, dbgdir);
	if(target.size == 0)
	{
		std::cerr << "Failed!" << std::endl;
		return 1;
	}
	
	meta_t *meta = new meta_t [target.size];
	std::memset(meta, 0, target.size * sizeof(meta_t));
	x86s::icode_t *icode = new x86s::icode_t [target.size];
	std::memset(icode, 0, target.size * sizeof(x86s::icode_t));

	do_decode(icode, meta, bin, target);
	
	scan_target_t starget;
	starget.target = &target;
	starget.meta = meta;
	starget.bin = bin;
	starget.icode = icode;
	std::set<U8> entrypoints;
	scanprocs_t sprocs;
	
	for(std::map<std::string, U8>::iterator i = target.exports.begin(); i != target.exports.end(); ++i)
	{
		// if there's a relocation at the export entrypoint, assume it's data and don't decode it.
		if(target.relocations.find(i->second) == target.relocations.end())
		{
			entrypoints.insert(i->second);
		}
	}
	
	scanner_t scanner;
	if(!scanner.scan(starget, entrypoints, true, sprocs))
	{
		delete [] icode;
		delete [] meta;
		delete [] bin;
		std::cerr << "Failed!" << std::endl;
		return 1;
	}
	
	std::cerr << " done" << std::endl;

	qadasm(s, starget, sprocs);
	
	delete [] icode;
	delete [] meta;

	delete [] bin;
	//std::cerr << "loaded: " << target.module << ": " << target.size << " bytes loaded" << std::endl;
	return 0;
}

⌨️ 快捷键说明

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