#include "image_util.hpp" #include "std.hpp" using namespace std; #ifndef DEMO #pragma pack(push, 1) struct Head { short machine, num_sects; int timedata, sym_table, num_syms; short opt_size, chars; }; struct Opts { short magic; char major, minor; int code_size, data_size, udata_size; int entry, code_base, data_base; int image_base, sect_align, file_align; short major_os, minor_os, major_image, minor_image, major_subsys, minor_subsys; int reserved; int image_size, headers_size, checksum; short subsys, dllchars; int stack_reserve, stack_commit, heap_reserve, heap_commit, loadflags; int dir_entries; }; struct DDir { int rva, size; }; struct Sect { char name[8]; int virt_size, virt_addr; //in mem int data_size, data_addr; //on disk int relocs, lines; //file ptrs short num_relocs, num_lines; int chars; }; struct Rdir { int chars, timedata; short major, minor, num_names, num_ids; }; struct Rent { int id, data; }; struct Rdat { int addr, size, cp, zero; }; #pragma pack(pop) struct Rsrc { int id; void* data; int data_sz; vector kids; Rsrc(int id, Rsrc* p) : id(id), data(0), data_sz(0) { if (p) p->kids.push_back(this); // cout<<"res id:"< sections; static Rsrc* rsrc_root; static const char* img_file; static void openRsrcDir(Section* s, int off, Rsrc* p) { char* data = (char*)s->data; Rdir* dir = (Rdir*)(data + off); Rent* ent = (Rent*)(dir + 1); for (int k = 0; k < dir->num_ids; ++ent, ++k) { Rsrc* r = new Rsrc(ent->id, p); if (ent->data < 0) { //a node - offset is another dir openRsrcDir(s, ent->data & 0x7fffffff, r); } else { //a leaf Rdat* dat = (Rdat*)(data + ent->data); // cout<<"dat addr:"<addr<<" size:"<size<size; void* src = dat->addr - s->sect.virt_addr + data; void* dest = new char[sz]; memcpy(dest, src, sz); r->data = dest; r->data_sz = sz; } } } static void openRsrcTree(Section* s) { rsrc_root = new Rsrc(0, 0); openRsrcDir(s, 0, rsrc_root); } static int rsrcSize(Rsrc* r) { if (r->data) return (sizeof(Rdat) + r->data_sz + 7) & ~7; int sz = sizeof(Rdir); for (int k = 0; k < r->kids.size(); ++k) { sz += sizeof(Rent) + rsrcSize(r->kids[k]); } return sz; } static void closeRsrcDir(Section* s, int off, Rsrc* p) { int t, k; char* data = (char*)s->data; Rdir* dir = (Rdir*)(data + off); memset(dir, 0, sizeof(Rdir)); dir->num_ids = p->kids.size(); Rent* ent = (Rent*)(dir + 1); //to end of dir... off += sizeof(Rdir) + sizeof(Rent) * p->kids.size(); t = off; //write entries for (k = 0; k < p->kids.size(); ++ent, ++k) { Rsrc* r = p->kids[k]; ent->id = r->id; ent->data = t; if (!r->data) ent->data |= 0x80000000; t += rsrcSize(r); } t = off; //write kids... for (k = 0; k < p->kids.size(); ++k) { Rsrc* r = p->kids[k]; if (!r->data) { closeRsrcDir(s, t, r); } else { Rdat* dat = (Rdat*)(data + t); dat->addr = s->sect.virt_addr + t + sizeof(Rdat); dat->size = r->data_sz; dat->zero = dat->cp = 0; memcpy(data + t + sizeof(Rdat), r->data, r->data_sz); } t += rsrcSize(r); } } static int fileAlign(int n) { return (n + (opts->file_align - 1)) & ~(opts->file_align - 1); } static int sectAlign(int n) { return (n + (opts->sect_align - 1)) & ~(opts->sect_align - 1); } static void closeRsrcTree(Section* s) { int virt_sz = rsrcSize(rsrc_root); int data_sz = fileAlign(virt_sz); int virt_delta = sectAlign(virt_sz) - sectAlign(s->sect.virt_size); int data_delta = fileAlign(virt_sz) - fileAlign(s->sect.virt_size); for (int k = 0; k < sections.size(); ++k) { Section* t = sections[k]; if (t->sect.virt_addr > s->sect.virt_addr) { t->sect.virt_addr += virt_delta; if (!strcmp(t->sect.name, ".reloc")) { ddir[5].rva = t->sect.virt_addr; } } if (t->sect.data_addr > s->sect.data_addr) { t->sect.data_addr += data_delta; } } ddir[2].size = virt_sz; opts->image_size += virt_delta; s->sect.virt_size = virt_sz; s->sect.data_size = data_sz; delete[] s->data; s->data = new char[data_sz]; closeRsrcDir(s, 0, rsrc_root); delete rsrc_root; rsrc_root = 0; } static Rsrc* findRsrc(int id, Rsrc* p) { for (int k = 0; k < p->kids.size(); ++k) { if (p->kids[k]->id == id) return p->kids[k]; } return 0; } static Rsrc* findRsrc(int type, int id, int lang) { Rsrc* r = findRsrc(type, rsrc_root); if (!r) return 0; r = findRsrc(id, r); if (!r) return 0; return findRsrc(lang, r); } static void loadImage(istream& in) { int k; //read stub in.seekg(0x3c); in.read((char*)&stub_sz, 4); stub_sz += 4; stub = new char[stub_sz]; in.seekg(0); in.read(stub, stub_sz); //read head head = new Head; head_sz = sizeof(Head); in.read((char*)head, head_sz); //read opts opts = new Opts; opts_sz = sizeof(Opts); in.read((char*)opts, opts_sz); //read data dirs ddir_sz = opts->dir_entries * sizeof(DDir); ddir = (DDir*)new char[ddir_sz]; in.read((char*)ddir, ddir_sz); //read sects... for (k = 0; k < head->num_sects; ++k) { Section* s = new Section; in.read((char*)&s->sect, sizeof(Sect)); sections.push_back(s); } for (k = 0; k < head->num_sects; ++k) { Section* s = sections[k]; if (!s->sect.data_addr) continue; int data_sz = s->sect.data_size; s->data = new char[data_sz]; //char[s->sect.virt_size]; //memset( s->data,0,s->sect.virt_size ); in.seekg(s->sect.data_addr); in.read(s->data, data_sz); } } static void saveImage(ostream& out) { int k; out.write((char*)stub, stub_sz); out.write((char*)head, head_sz); out.write((char*)opts, opts_sz); out.write((char*)ddir, ddir_sz); for (k = 0; k < head->num_sects; ++k) { Section* s = sections[k]; out.write((char*)&s->sect, sizeof(Sect)); } for (k = 0; k < head->num_sects; ++k) { Section* s = sections[k]; if (!s->sect.data_addr) continue; //assumes sect data is in order!!!!! while (out.tellp() < s->sect.data_addr) out.put((char)0xbb); out.seekp(s->sect.data_addr); out.write(s->data, s->sect.data_size); } } /********************** PUBLIC STUFF ***********************/ bool openImage(const char* img) { img_file = img; fstream in(img_file, ios_base::binary | ios_base::in); loadImage(in); in.close(); return true; } bool makeExe(int entry) { if (!img_file) return false; head->chars |= 0x0002; //executable head->chars &= ~0x2000; //not Dll opts->entry = entry; // opts->image_base=0x400000; //have to deal to fix-ups to do this properly. return true; } bool replaceRsrc(int type, int id, int lang, void* data, int data_sz) { if (!img_file) return false; for (int k = 0; k < sections.size(); ++k) { Section* s = sections[k]; if (strcmp(s->sect.name, ".rsrc")) continue; openRsrcTree(s); if (Rsrc* r = findRsrc(type, id, lang)) { delete[] r->data; r->data_sz = data_sz; r->data = new char[data_sz]; memcpy(r->data, data, data_sz); closeRsrcTree(s); return true; } closeRsrcTree(s); } return false; } void closeImage() { if (!img_file) return; fstream out(img_file, ios_base::binary | ios_base::out | ios_base::trunc); saveImage(out); out.close(); for (; sections.size(); sections.pop_back()) delete sections.back(); delete[] ddir; delete opts; delete head; delete[] stub; img_file = 0; } #endif