📄 qadasm.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 = ⌖
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 + -