void PEObject::WriteHeader(std::fstream &stream) { unsigned zero = 0; for (int i =0; i < name.size() && i < 8; i++) stream.write(&name[i], 1); for (int i = name.size(); i < 8; i++) stream.write((char *)&zero, 1); unsigned msize = ObjectAlign(objectAlign, size); stream.write((char *)&msize, 4); stream.write((char *)&virtual_addr, 4); msize = ObjectAlign(fileAlign, initSize); stream.write((char *)&msize, 4); stream.write((char *)&raw_addr, 4); stream.write((char *)&zero, 4); stream.write((char *)&zero, 4); stream.write((char *)&zero, 4); int flg = (flags ^ WINF_NEG_FLAGS) & WINF_IMAGE_FLAGS; /* get characteristice for section */ stream.write((char *)&flg, 4); }
void PEObject::Write(std::fstream &stream) { stream.write((char *)data, initSize); int n = ObjectAlign(fileAlign, initSize) - initSize; char buf[512]; memset(buf,0, sizeof(buf)); while (n > 0) { int s = sizeof(buf); if (n < s) s = n; stream.write(buf, s); n -= s; } }
void PEImportObject::Setup(ObjInt &endVa, ObjInt &endPhys) { if (virtual_addr == 0) { virtual_addr = endVa; } else { if (virtual_addr != endVa) Utils::fatal("Internal error"); } raw_addr = endPhys; std::map<ObjString, ObjSymbol *> externs; for (ObjFile::SymbolIterator it = file->ExternalBegin(); it != file->ExternalEnd(); ++it) { externs[(*it)->GetName()] = (*it); } std::map<std::string, Module *> modules; int nameSize = 0; int impNameSize = 0; int importCount = 0; int dllCount = 0; for (ObjFile::SymbolIterator it = file->ImportBegin(); it != file->ImportEnd(); ++it) { ObjImportSymbol *s = (ObjImportSymbol *)(*it); // uppercase the module name for NT... 98 doesn't need it but can accept it std::string name = s->GetDllName(); for (int i =0; i < name.size(); i++) name[i] = toupper(name[i]); s->SetDllName(name); if (externs.find((*it)->GetName()) != externs.end()) { Module *m = modules[s->GetDllName()]; int sz = s->GetDllName().size() + 1; if (sz & 1) sz ++; nameSize += sz; if (m == NULL) { modules[s->GetDllName()] = m = new Module; m->module = s->GetDllName(); dllCount++; } if (s->GetExternalName().size() == 0) { m->externalNames.push_back(s->GetName()); sz = s->GetName().size() + 1; } else { m->externalNames.push_back(s->GetExternalName()); sz = s->GetExternalName().size() + 1; } sz += 2; if (sz & 1) sz ++; impNameSize += sz; m->publicNames.push_back(s->GetName()); m->ordinals.push_back(s->GetByOrdinal() ? s->GetOrdinal() : 0xffffffff); importCount ++; } } data = new unsigned char[(modules.size() + 1) * sizeof(Dir) + ((nameSize + 3) & ~3) + (importCount + dllCount) * sizeof(Entry) * 2 + ((impNameSize + 3) & ~3)]; Dir *dirPos = (Dir *)data; char *namePos = (char *)data + sizeof(Dir) * (modules.size() + 1); Entry *lookupPos = (Entry *)((char *)namePos + ((nameSize + 3) & ~3)); char *hintPos = ((char *)lookupPos) + (importCount + dllCount) * sizeof(Entry); Entry *addressPos = (Entry *)(hintPos + ((impNameSize + 3) & ~3)); size = initSize = (unsigned)(((unsigned char *)addressPos) - data + (importCount + dllCount) * sizeof(Entry)); memset(data, 0, size); // note this does clean out some areas we deliberately are not initializing for (std::map<std::string, Module *>::iterator it = modules.begin(); it != modules.end(); ++it) { dirPos->time = 0; dirPos->version = 0; dirPos->dllName = (unsigned char *)namePos - data + virtual_addr; dirPos->thunkPos = ((unsigned char *)lookupPos) - data + virtual_addr; dirPos->thunkPos2 = ((unsigned char *)addressPos) - data + virtual_addr; dirPos++; strcpy(namePos, it->first.c_str()); int n = it->first.size() + 1; if (n & 1) n++; namePos += n; for (int i = 0; i < it->second->externalNames.size(); i++) { const std::string &str = it->second->externalNames[i]; if (str.size()) { lookupPos->ord_or_rva = (unsigned char *)hintPos - data + virtual_addr; addressPos->ord_or_rva = (unsigned char *) hintPos - data + virtual_addr; *(short *)hintPos = 0; //it->second->ordinals[i]; hintPos += 2; strcpy(hintPos, str.c_str()); int n = str.size() + 1; if (n & 1) n++; hintPos += n; } else { lookupPos->ord_or_rva = addressPos->ord_or_rva = it->second->ordinals[i] | IMPORT_BY_ORDINAL; } // next up we make a thunk that will get us from the rel calls genned by // the compiler to the import table; ObjSymbol *sym = externs[it->second->publicNames[i]]; int en = sym->GetIndex(); for (std::deque<PEObject *>::iterator it1 = objects.begin(); it1 != objects.end(); ++ it1) { ObjInt val; if ((val = (*it1)->SetThunk(en, ((unsigned char *)lookupPos) - data + virtual_addr + imageBase)) != -1) sym->SetOffset(new ObjExpression(val)); } lookupPos++; addressPos++; } // skip the null entry at the end of a module lookupPos++; addressPos++; } for (std::map<std::string, Module *>::iterator it = modules.begin(); it != modules.end(); ++it) { Module *p = it->second; delete p; } endVa = ObjectAlign(objectAlign, endVa + size); endPhys = ObjectAlign(fileAlign, endPhys + initSize); }
void PEFixupObject::Setup(ObjInt &endVa, ObjInt &endPhys) { if (virtual_addr == 0) { virtual_addr = endVa; } else { if (virtual_addr != endVa) Utils::fatal("Internal error"); } raw_addr = endPhys; if (fixups.size() == 0) { // for WINNT, he needs some reloc data even if it is empty... Block block; block.rva = 0; block.size = 12; block.data[0] = block.data[1] = 0; data = new unsigned char[block.size]; memcpy(data, &block, block.size); size = initSize = block.size; } else { int base = -1; initSize = 0; for (auto fixup : fixups) { if ((base ^ fixup) & ~4095) { if (initSize & 2) initSize += 2; initSize += 8; base = fixup; } initSize += 2; } if (initSize & 2) initSize += 2; size = initSize; data = new unsigned char[initSize]; memset(data, 0, initSize); // we relied on the set implementation to sort the fixups... int curSize = 0; Block *block = (Block *)data; for (auto it = fixups.begin(); it != fixups.end();) { ObjInt base = (*it) & ~(4096 - 1); int current = 0; block->rva = base - imageBase; block->size = 8; while (it != fixups.end() && ((*it) & ~(4096 - 1)) == base) { block->size+=2; block->data[current++] = ((*it) & (4096 -1)) + ( PE_FIXUP_HIGHLOW << 12); ++it; } if (block->size & 2) { block->size += 2; block->data[current++] = 0; } block = (Block *)((unsigned char *)block + block->size); } } endVa = ObjectAlign(objectAlign, endVa + size); endPhys = ObjectAlign(fileAlign, endPhys + initSize); }
void PEExportObject::Setup(ObjInt &endVa, ObjInt &endPhys) { if (virtual_addr == 0) { virtual_addr = endVa; } else { if (virtual_addr != endVa) Utils::fatal("Internal error"); } raw_addr = endPhys; std::map<std::string, ObjInt> publics; for (ObjFile::SymbolIterator it = file->PublicBegin(); it != file->PublicEnd(); ++it) { publics[(*it)->GetName()] = (*it)->GetOffset()->Eval(0); } int pos = moduleName.find_last_of("\\"); if (pos == std::string::npos) { pos = moduleName.find_last_of(":"); if (pos == std::string::npos) pos = 0; } std::string name = moduleName.substr(pos); size = initSize = sizeof(Header) + 1 + name.size(); unsigned minOrd=0xffffffff; /* max ordinal num */ unsigned maxOrd=0; unsigned count = 0; std::set<ObjExportSymbol *, namelt> names; for (ObjFile::SymbolIterator it = file->ExportBegin(); it != file->ExportEnd(); ++it) { ObjExportSymbol *s = (ObjExportSymbol *)(*it); names.insert(s); if (!s->GetByOrdinal()) { initSize = (size += s->GetName().size() + 1 + 6); } if (s->GetOrdinal() != 0xffffffff) { int n = s->GetOrdinal(); if (n < minOrd) minOrd = n; if (n > maxOrd) maxOrd = n; } count++; } if (maxOrd >= minOrd) { count = count > (maxOrd-minOrd + 1) ? count : maxOrd-minOrd + 1; } else { minOrd = 1; maxOrd = count + minOrd - 1; } initSize = (size += 4 * count); data = new unsigned char[initSize]; memset(data, 0, initSize); Header *header = (Header *)data; header->time = time(0); header->ord_base = minOrd; header->n_eat_entries = count; header->n_name_ptrs = names.size(); unsigned *rvaTable = (unsigned *)(data + sizeof(Header)); unsigned *nameTable = (unsigned *)(((unsigned char *)rvaTable) + 4 * count); unsigned short *ordinalTable = (unsigned short *)(((unsigned char *)nameTable) + 4 * names.size()); unsigned char *stringTable = (unsigned char *)(((unsigned char *)ordinalTable) + 2 * names.size()); header->address_rva = virtual_addr + ((unsigned char *)rvaTable) - data; header->name_rva = virtual_addr + ((unsigned char *)nameTable) - data; header->ordinal_rva = virtual_addr + ((unsigned char *)ordinalTable) - data; /* process numbered exports */ for (ObjFile::SymbolIterator it = file->ExportBegin(); it != file->ExportEnd(); ++it) { ObjExportSymbol *s = (ObjExportSymbol *)(*it); if (s->GetByOrdinal()) { int n = s->GetOrdinal(); if (rvaTable[n - minOrd] != 0) std::cout << "Warning: Export '" << s->GetName() << "' duplicates an ordinal" << std::endl; int addr = publics[s->GetName()]; if (addr == 0) std::cout << "Warning: Export '" << s->GetName() << "' has no related public" << std::endl; rvaTable[n - minOrd] = addr - imageBase; } } /* process non-numbered exports */ pos = 0; for (ObjFile::SymbolIterator it = file->ExportBegin(); it != file->ExportEnd(); ++it) { ObjExportSymbol *s = (ObjExportSymbol *)(*it); if (!s->GetByOrdinal()) { while(rvaTable[pos]) pos++; s->SetOrdinal(pos + minOrd); int addr = publics[s->GetName()]; if (addr == 0) std::cout << "Warning: Export '" << s->GetName() << "' has no related public" << std::endl; rvaTable[pos] = addr - imageBase; } } // process named exports for (std::set<ObjExportSymbol *, namelt>::iterator it = names.begin(); it != names.end(); ++it) { *nameTable++ = (unsigned)((unsigned char *)stringTable - data + virtual_addr); *ordinalTable++ = (*it)->GetOrdinal() - minOrd; strcpy((char *)stringTable, (*it)->GetName().c_str()); stringTable += (*it)->GetName().size(); *stringTable++ = 0; } // throw in the DLL name if (name.size()) { header->exe_name_rva = (unsigned)((unsigned char *)stringTable - data + virtual_addr); for (int i=0; i < name.size(); i++) *stringTable++ = toupper(name[i]); *stringTable++ = 0; } endVa = ObjectAlign(objectAlign, endVa + size); endPhys = ObjectAlign(fileAlign, endPhys + initSize); }