Skip to content

Instantly share code, notes, and snippets.

@indirivacua
Created December 20, 2019 00:07
Show Gist options
  • Save indirivacua/3559cf2a4e0b8a7ad993356c8143a645 to your computer and use it in GitHub Desktop.
Save indirivacua/3559cf2a4e0b8a7ad993356c8143a645 to your computer and use it in GitHub Desktop.
// http://brmodstudio.forumeiros.com
// http://brmodstudio.forumeiros.com
// http://brmodstudio.forumeiros.com
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <memory>
#include <vector>
#include <string>
#include <map>
#include <utility>
#include <optional>
#include <sstream>
#include <Windows.h>
#include "CText.h"
#include <cctype>
std::string& str_replace(const std::string &search, const std::string &replace, std::string &subject)
{
std::string buffer;
const int sealeng = search.length();
const int strleng = subject.length();
if (sealeng == 0)
return subject;//no change
for (int i = 0, j = 0; i<strleng; j = 0)
{
while (i + j<strleng && j<sealeng && subject[i + j] == search[j])
j++;
if (j == sealeng)//found 'search'
{
buffer.append(replace);
i += sealeng;
}
else
{
buffer.append(&subject[i++], 1);
}
}
subject = buffer;
return subject;
}
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
std::string compileCMD = "F:/MinGW/bin/g++.exe -c %0 -fno-exceptions -IF:\MinGW\include -IF:\MinGW\i686-w64-mingw32\include -IF:\MinGW\i686-w64-mingw32\include\c++ -IF:\MinGW\i686-w64-mingw32\include\c++\i686-w64-mingw32 -IF:\MinGW\lib\gcc\i686-w64-mingw32\4.8.3\include -nostdlib -std=c++11 -shared -masm=intel -o %1";
std::string compileCMD2 = "F:/MinGW/bin/g++.exe -c new.cpp -fno-exceptions -IF:\MinGW\include -IF:\MinGW\i686-w64-mingw32\include -IF:\MinGW\i686-w64-mingw32\include\c++ -IF:\MinGW\i686-w64-mingw32\include\c++\i686-w64-mingw32 -IF:\MinGW\lib\gcc\i686-w64-mingw32\4.8.3\include -nostdlib -std=c++11 -shared -masm=intel -o testnew.o";
bool debugOn = false;
bool outputToGTA3SCFormat = false;
bool exportList = true, exportOtherFunctions = false;
int rellocOffset = 0;
std::vector<std::string> exports;
void executeCommand(const std::string &command)
{
system(command.c_str());
}
#pragma pack(push, 1)
union COFFNameUnion
{
char str[8];
struct
{
unsigned long zeroes;
unsigned long offset;
};
};
// COFF file structures, thanks to http://wiki.osdev.org/COFF
struct COFFHeader {
unsigned short f_magic; /* Magic number */
unsigned short f_nscns; /* Number of Sections */
long f_timdat; /* Time & date stamp */
long f_symptr; /* File pointer to Symbol Table */
long f_nsyms; /* Number of Symbols */
unsigned short f_opthdr; /* sizeof(Optional Header) */
unsigned short f_flags; /* Flags */
};
struct COFFOptionalHeader {
unsigned short magic; /* Magic Number */
unsigned short vstamp; /* Version stamp */
unsigned long tsize; /* Text size in bytes */
unsigned long dsize; /* Initialised data size */
unsigned long bsize; /* Uninitialised data size */
unsigned long entry; /* Entry point */
unsigned long text_start; /* Base of Text used for this file */
unsigned long data_start; /* Base of Data used for this file */
};
enum COFFSectionHeaderType { STYP_TEXT = 0x20, STYP_DATA = 0x40, STYP_BSS = 0x80};
long COFFSectionHeaderTypes = STYP_TEXT | STYP_DATA | STYP_BSS;
struct COFFSectionHeader {
COFFNameUnion s_name; /* Section Name */
long s_paddr; /* Physical Address */
long s_vaddr; /* Virtual Address */
long s_size; /* Section Size in Bytes */
long s_scnptr; /* File offset to the Section data */
long s_relptr; /* File offset to the Relocation table for this Section */
long s_lnnoptr; /* File offset to the Line Number table for this Section */
unsigned short s_nreloc; /* Number of Relocation table entries */
unsigned short s_nlnno; /* Number of Line Number table entries */
long s_flags; /* Flags for this section */
};
struct COFFRealocationsEntries {
long r_vaddr; /* Reference Address */
long r_symndx; /* Symbol index */
unsigned short r_type; /* Type of relocation */
//unsigned short offset; /* offset */
};
struct COFFLineNumberEntries {
union
{
long l_symndx; /* Symbol Index */
long l_paddr; /* Physical Address */
} l_addr;
unsigned short l_lnno; /* Line Number */
};
struct COFFSymbolTable
{
COFFNameUnion name;
long n_value; /* Value of Symbol */
short n_scnum; /* Section Number */
unsigned short n_type; /* Symbol Type */
char n_sclass; /* Storage Class */
char n_numaux; /* Auxiliary Count */
};
struct COFFSectionHeaderCPP
{
COFFSectionHeader rawSectionHeader;
std::unique_ptr<COFFRealocationsEntries[]> rawRealocationsEntries;
std::unique_ptr<COFFLineNumberEntries[]> rawLineNumberEntries;
std::unique_ptr<char[]> sectionData;
};
struct writtenSymbols
{
COFFSymbolTable *symbol;
int address;
std::streampos filePos;
};
#pragma pack(pop)
class COFFFile {
public:
COFFHeader header;
COFFOptionalHeader optionalHeader;
std::unique_ptr<COFFSectionHeaderCPP[]> sectionsHeader;
std::unique_ptr<COFFSymbolTable[]> symbolTable;
std::map<long, std::string> stringData;
std::vector<writtenSymbols> wSymbols;
bool open;
COFFFile()
{
open = false;
}
int getNumSections() const
{
return header.f_nscns;
}
int getNumSymbols() const
{
return header.f_nsyms;
}
std::string getFullName(const COFFNameUnion &n) const
{
std::string result = "Fail to get name";
if (n.zeroes != 0)
{
int num = 8;
if (n.str[7] == 0)
num = strlen(n.str);
result = "";
result.insert(0, n.str, num);
}
else
{
auto off = stringData.find(n.offset);
if (off != stringData.end())
result = off->second;
}
return result;
}
std::string getSectionName(int id) const
{
if (getNumSections() <= id)
return "Fail to get name";
return getFullName(sectionsHeader[id].rawSectionHeader.s_name);
}
std::string getSymbolName(int id) const
{
if (getNumSymbols() <= id)
return "Fail to get name";
return getFullName(symbolTable[id].name);
}
COFFSymbolTable &getSymbolByName(const std::string &name)
{
for (int i = 0; i < getNumSymbols(); i++)
{
if (getFullName(symbolTable[i].name) == name)
{
return symbolTable[i];
}
}
throw std::runtime_error(std::string(__FILE__) + " " + std::to_string(__LINE__));
}
};
COFFFile openCOFFFile(const std::string &file)
{
COFFFile COFFfile;
std::fstream test(file, std::ios::in | std::ios::binary);
if (!test.is_open())
{
std::cout << "Fail to open the file" << std::endl;
return COFFfile;
}
COFFfile.open = true;
test.seekg(0, std::ios::beg);
test.read(reinterpret_cast<char*>(&COFFfile.header), sizeof(COFFfile.header));
//std::cout << header.f_opthdr << std::endl;
//std::cout << header.f_nscns << std::endl;
if (COFFfile.header.f_opthdr != 0)
{
test.read(reinterpret_cast<char*>(&COFFfile.optionalHeader), sizeof(COFFfile.optionalHeader));
}
COFFfile.sectionsHeader = std::make_unique<COFFSectionHeaderCPP[]>(COFFfile.header.f_nscns);
COFFfile.symbolTable = std::make_unique<COFFSymbolTable[]>(COFFfile.header.f_nsyms);
{
auto sectionsHeaderPointer = COFFfile.sectionsHeader.get();
for (int i = 0; i < COFFfile.header.f_nscns; i++)
{
auto &sectionHeader = sectionsHeaderPointer[i];
test.read(reinterpret_cast<char*>(&(sectionHeader.rawSectionHeader)), sizeof(COFFSectionHeader));
}
for (int i = 0; i < COFFfile.header.f_nscns; i++)
{
auto &sectionHeader = sectionsHeaderPointer[i];
/*std::cout << "Section name " << sectionHeader.rawSectionHeader.s_name << " Section size " << sectionHeader.rawSectionHeader.s_size
<< " lines num " << sectionHeader.rawSectionHeader.s_nlnno
<< " relocations num " << sectionHeader.rawSectionHeader.s_nreloc
<< " type " << (sectionHeader.rawSectionHeader.s_flags & COFFSectionHeaderTypes) << std::endl;*/
if (sectionHeader.rawSectionHeader.s_scnptr > 0 && sectionHeader.rawSectionHeader.s_size > 0)
{
sectionHeader.sectionData = std::make_unique<char[]>(sectionHeader.rawSectionHeader.s_size);
test.seekg(sectionHeader.rawSectionHeader.s_scnptr, std::ios::beg);
test.read(sectionHeader.sectionData.get(), sectionHeader.rawSectionHeader.s_size);
}
if (sectionHeader.rawSectionHeader.s_nreloc > 0)
{
sectionHeader.rawRealocationsEntries = std::make_unique<COFFRealocationsEntries[]>(sectionHeader.rawSectionHeader.s_nreloc);
test.seekg(sectionHeader.rawSectionHeader.s_relptr, std::ios::beg);
test.read(reinterpret_cast<char*>(sectionHeader.rawRealocationsEntries.get()), sizeof(COFFRealocationsEntries) * sectionHeader.rawSectionHeader.s_nreloc);
}
if (sectionHeader.rawSectionHeader.s_nlnno > 0)
{
sectionHeader.rawLineNumberEntries = std::make_unique<COFFLineNumberEntries[]>(sectionHeader.rawSectionHeader.s_nlnno);
test.seekg(sectionHeader.rawSectionHeader.s_lnnoptr, std::ios::beg);
test.read(reinterpret_cast<char*>(sectionHeader.rawLineNumberEntries.get()), sizeof(COFFLineNumberEntries) * sectionHeader.rawSectionHeader.s_nlnno);
}
}
}
// Read symbols table
test.seekg(COFFfile.header.f_symptr, std::ios::beg);
test.read(reinterpret_cast<char*>(COFFfile.symbolTable.get()), sizeof(COFFSymbolTable) * COFFfile.header.f_nsyms);
int32_t mem = 0;
test.read(reinterpret_cast<char*>(&mem), sizeof(mem));
std::unique_ptr<char[]> strings = std::make_unique<char[]>(mem);
const int memTest = (mem - 4);
{
memset(strings.get(), 0, 4);
test.read(strings.get() + 4, mem - 4);
char *s = strings.get();
for (int i = 0; i < memTest; i++)
{
if (i >= memTest)
{
break;
}
COFFfile.stringData[i] = &s[i];
int len = strlen(&s[i]);
i += len;
while (i < memTest)
{
if (s[i] == 0)
{
i++;
}
else
{
i--;
break;
}
}
}
}
for (int i = 0; i < COFFfile.header.f_nsyms; i++)
{
/*COFFSymbolTable &symbtable = COFFfile.symbolTable[i];
if (symbtable.name.zeroes != 0 && symbtable.name.str[0] > 0 && isprint(symbtable.name.str[0]))
{
std::cout << symbtable.name.str << std::endl;
}
else
{
if (symbtable.name.offset && symbtable.name.offset < memTest)
{
std::cout << "zeroes " << symbtable.name.zeroes << std::endl;
std::cout << "offset " << symbtable.name.offset << std::endl;
std::cout << " " << COFFfile.stringData[symbtable.name.offset] << std::endl;
}
}*/
}
return COFFfile;
}
void makeCall(std::vector<uint8_t> &data, int absoluteTargetAddress)
{
int32_t calc = data.size();
calc += 5;
calc = absoluteTargetAddress - calc;
data.push_back(0xE8);
uint8_t *calcPtr = reinterpret_cast<uint8_t*>(&calc);
data.insert(data.end(), calcPtr, calcPtr + sizeof(calc));
}
void makeExternalCall(std::vector<uint8_t> &data, uint32_t absoluteTargetAddress)
{
uint8_t asmData[] = {
0x68, 0x00, 0x00, 0x00, 0x00,
0xC3
};
*reinterpret_cast<uint32_t*>(&asmData[1]) = absoluteTargetAddress;
data.insert(data.end(), asmData, asmData + (sizeof(asmData) / sizeof(uint8_t)));
}
void makeExternalCallPushAddress(std::vector<uint8_t> &data, uint32_t absoluteTargetAddress)
{
uint8_t asmData[] = {
0x00, 0x00, 0x00, 0x00
};
*reinterpret_cast<uint32_t*>(&asmData[0]) = absoluteTargetAddress;
data.insert(data.end(), asmData, asmData + (sizeof(asmData) / sizeof(uint8_t)));
}
writtenSymbols getSymbolForReAlloc(const COFFFile &file, int symbolId)
{
writtenSymbols result{0, 0, 0};
if (file.getNumSymbols() > symbolId)
{
auto &symbol = file.symbolTable[symbolId];
for (auto &ws : file.wSymbols)
{
if (std::addressof(symbol) == ws.symbol)
return ws;
}
}
return result;
}
struct scriptSymbols
{
std::string name;
int pos;
int COFFid;
scriptSymbols()
{
pos = 0;
COFFid = -1;
}
};
std::vector<scriptSymbols> symbols;
scriptSymbols &getSymbolByName(const std::string &name)
{
for (int i = 0; i < symbols.size(); i++)
{
if (symbols[i].name == name)
{
return symbols[i];
}
}
throw std::runtime_error(std::string(__FILE__) + " " + std::to_string(__LINE__));
}
std::optional<scriptSymbols> symbolForIndex(int index)
{
for (auto &s : symbols)
{
if (s.pos == index)
{
return s;
}
}
return std::nullopt;
}
std::string outputStartHex()
{
if (outputToGTA3SCFormat)
{
return "DUMP";
}
return "HEX";
}
std::string outputEndHex()
{
if (outputToGTA3SCFormat)
{
return "ENDDUMP";
}
return "END";
}
std::string labelFormat(const std::string &label)
{
if (outputToGTA3SCFormat)
{
return label + ":";
}
return ":" + label;
}
bool mustExportThisSymbol(const std::string &symbolName)
{
if (symbolName.size() == 0)
return false;
if (symbolName == "_initCPPCode")
{
return true;
}
std::string s = symbolName;
if (s[0] == '_')
s[0] = ' ';
trim(s);
//std::cout << s << s.size() << std::endl;
auto it = std::find(exports.begin(), exports.end(), s);
if (it != exports.end())
{
//std::cout << "it true" << std::endl;
return true;
}
return false;
}
void vectorDataToFile(COFFFile &coff, std::fstream &fout, std::vector<uint8_t> &data)
{
int breakLineCount = 0;
// TODO: find .drectve section
bool DUMP = false, firstDUMP = false;
for (int i = 0; i < data.size(); i++, breakLineCount++)
{
auto &ch = data[i];
auto sn = symbolForIndex(i);
if (sn)
{
auto symbol = sn.value();
if (mustExportThisSymbol(symbol.name) && (symbol.COFFid == -1 || (symbol.COFFid >= 0 && coff.symbolTable[symbol.COFFid].n_type == 32)))
{
if (DUMP)
{
fout << std::endl;
fout << outputEndHex() << "\n";
}
fout << std::endl;
fout << labelFormat(symbol.name) << "\n";
fout << outputStartHex() << "\n";
breakLineCount = 0;
DUMP = true;
firstDUMP = true;
}
}
if (!firstDUMP)
{
fout << outputStartHex() << "\n";
firstDUMP = true;
DUMP = true;
}
fout << std::hex << (ch < 0x10 ? "0" : "") << (int)(ch) << " ";
if (breakLineCount >= 60)
{
fout << std::endl;
breakLineCount = 0;
}
}
}
void pushSymbolForSection(const COFFFile &file, int section, int value, int bytes)
{
for (int l = 0; l < file.getNumSymbols(); l++)
{
auto &symbol = file.symbolTable[l];
//std::cout << symbol.n_type << std::endl;
if ((symbol.n_scnum - 1) == section && /*symbol.n_type > 0 &&*/ symbol.n_value == value)
{
scriptSymbols ns;
ns.name = file.getFullName(symbol.name);
ns.pos = bytes;
ns.COFFid = l;
//std::cout << ns.name << std::endl;
//std::cout << bytes << std::endl;
//std::cout << value << std::endl;
//std::cout << l << std::endl;
symbols.push_back(std::move(ns));
}
}
}
void listSymbols(const COFFFile &file)
{
for (int l = 0; l < file.getNumSymbols(); l++)
{
auto &symbol = file.symbolTable[l];
{
std::cout << file.getFullName(symbol.name) << std::endl;
std::cout << l << std::endl;
}
}
}
struct reallocationTable
{
int32_t offset;
int32_t symbol;
int32_t type;
reallocationTable()
{
offset = symbol = type = 0;
}
reallocationTable(const COFFRealocationsEntries &entry)
{
offset = entry.r_vaddr;
symbol = entry.r_symndx;
type = entry.r_type;
}
};
struct reallocationTableToFile
{
int32_t offset;
int32_t symbol;
reallocationTableToFile()
{
offset = symbol = 0;
}
reallocationTableToFile(const reallocationTable &entry)
{
offset = entry.offset;
symbol = entry.symbol;
}
};
std::vector<reallocationTable> rellocations;
enum externalSymbolsType {textFunction, dataFunction};
struct externalObjectList
{
uint32_t address;
int type;
externalObjectList()
{
address = 0;
type = 0;
}
};
std::map<std::string, externalObjectList> externalObjects;
const std::map<std::string, externalObjectList> &getExternalObjectsList()
{
return externalObjects;
}
void parseDrective(const char *p, int size)
{
if (p && size > 0)
{
std::string str(p, p + size);
std::replace(str.begin(), str.end(), ' ', '\n');
std::replace(str.begin(), str.end(), ' ', '\n');
str_replace("-export:\"", "\n", str);
std::replace(str.begin(), str.end(), '"', '\n');
trim(str);
std::stringstream s(str);
std::string temp;
while (std::getline(s, temp))
{
trim(temp);
if (temp.size() == 0)
continue;
//std::cout << temp << temp.size() << std::endl;
exports.push_back(temp);
}
}
}
void loadSymbolList()
{
std::cout << "Tentando carregar SymbolList.txt..." << std::endl;
std::string test;
{
std::fstream symbolList("SymbolList.txt", std::ios::in | std::ios::binary);
if (symbolList.fail())
{
std::cout << "Falha ao abrir o arquivo SymbolList.txt" << std::endl << std::endl;
return;
}
symbolList.seekg(0, std::ios::end);
size_t size = symbolList.tellg();
symbolList.seekg(0, std::ios::beg);
test.insert(0, size, '\n');
symbolList.read(test.data(), size);
}
std::stringstream contents(std::move(test));
char line[1024];
while (contents.getline(line, sizeof(line)))
{
char funame[128], sect[64];
uint32_t addr;
int r = sscanf(line, "%s %s %x", funame, sect, &addr);
if (r == 3)
{
auto &nSymbol = externalObjects[funame];
nSymbol.address = addr;
nSymbol.type = externalSymbolsType::textFunction;
if (std::string(sect).find("data") != std::string::npos)
{
nSymbol.type = externalSymbolsType::dataFunction;
}
}
}
}
template<class T>
void printbits(T c)
{
for (int i = 0; i < (sizeof(T) * 8); i++)
{
const uint64_t b = pow(2, i);
std::cout << ((c & b) != 0);
}
}
void toCLEOSCM(COFFFile &COFFfile, const std::string &outFinalFile)
{
rellocations.clear();
symbols.clear();
exports.clear();
if (COFFfile.open)
{
std::fstream fout(outFinalFile, std::ios::out | std::ios::trunc);
if (fout.is_open())
{
std::vector<uint8_t> outputData;
{
externalObjectList nobj;
nobj.address = 0x00588BE0;
nobj.type = 0;
externalObjects["_showTextBox"] = nobj;
}
{
{
scriptSymbols ns;
ns.name = "getCodeTopAddress";
ns.pos = outputData.size();
symbols.push_back(ns);
}
uint8_t ab[] = { 0xE8u, 0x01u, 0x00u, 0x00u, 0x00u, 0xC3u, 0x8Bu, 0x04u, 0x24u, 0x83u, 0xE8u, 0x05u, 0xC3u };
outputData.insert(outputData.end(), ab, ab + (sizeof(ab) / sizeof(uint8_t)));
}
for (int i = 0; i < COFFfile.getNumSections(); i++)
{
auto &section = COFFfile.sectionsHeader[i];
if (COFFfile.getSectionName(i) == ".drectve")
{
//std::cout << (section.rawSectionHeader.s_flags & (STYP_TEXT | STYP_DATA | STYP_BSS)) << std::endl << std::endl;
parseDrective(section.sectionData.get(), section.rawSectionHeader.s_size);
continue;
}
if (section.rawSectionHeader.s_nreloc > 0)
{
auto reloc = section.rawRealocationsEntries.get();
for (int i = 0; i < section.rawSectionHeader.s_nreloc; i++)
{
reallocationTable r = reloc[i];
r.offset += outputData.size();
//std::cout << reloc[i].offset << std::endl;
rellocations.push_back(r);
}
}
if (section.rawSectionHeader.s_flags & STYP_TEXT)
{
auto data = section.sectionData.get();
for (int j = 0; j < section.rawSectionHeader.s_size; j++)
{
uint8_t ubyte = static_cast<uint8_t>(data[j]);
pushSymbolForSection(COFFfile, i, j, outputData.size());
outputData.push_back(ubyte);
}
}
if (section.rawSectionHeader.s_flags & STYP_DATA)
{
auto data = section.sectionData.get();
for (int j = 0; j < section.rawSectionHeader.s_size; j++)
{
uint8_t ubyte = static_cast<uint8_t>(data[j]);
pushSymbolForSection(COFFfile, i, j, outputData.size());
outputData.push_back(ubyte);
}
}
if (section.rawSectionHeader.s_flags & STYP_BSS)
{
for (int j = 0; j < section.rawSectionHeader.s_size; j++)
{
pushSymbolForSection(COFFfile, i, j, outputData.size());
outputData.push_back(0x00);
}
}
}
for (int i = 0; i < COFFfile.getNumSymbols(); i++)
{
auto &symbol = COFFfile.symbolTable[i];
if (symbol.n_scnum == 0) {
auto objFullName = COFFfile.getFullName(symbol.name);
/*std::cout << objFullName << std::endl;
std::cout << "n_type " << symbol.n_type << std::endl;
std::cout << "n_value " << symbol.n_value << std::endl;
std::cout << "n_scnum " << symbol.n_scnum << std::endl;*/
auto &eobj = getExternalObjectsList();
auto it = eobj.find(objFullName);
if (it != eobj.end())
{
{
scriptSymbols ns;
ns.name = objFullName;
ns.pos = outputData.size();
ns.COFFid = i;
symbols.push_back(std::move(ns));
}
switch (it->second.type)
{
case 0:
makeExternalCall(outputData, it->second.address);
break;
case 1:
makeExternalCallPushAddress(outputData, it->second.address);
break;
case 2:
break;
default:
break;
}
}
else
{
std::cout << "Undefined external: " << COFFfile.getSymbolName(i) << std::endl;
}
}
}
int reallocationFunctionPos = 0;
{
scriptSymbols ns;
ns.name = "reallocationFunction";
ns.pos = outputData.size();
reallocationFunctionPos = ns.pos;
symbols.push_back(std::move(ns));
/*
#include <cstdint>
struct reallocationTable
{
int32_t offset;
int32_t symbol;
int32_t type;
};
extern "C" void volatile reallocationFunction(char *codeTop)
{
char *tablePos = codeTop;
tablePos += 0x10000;
reallocationTable *table = reinterpret_cast<reallocationTable*>(tablePos);
int tableSize = 1000;
for (int i = 0; i < tableSize; i++)
{
auto &tb = table[i];
int32_t **value = reinterpret_cast<int32_t**>(&codeTop[tb.offset]);
*value = reinterpret_cast<int32_t*>(&codeTop[tb.symbol]);
}
}
*/
int startPos = outputData.size();
uint8_t reallocationFunCode[] = {
/* 11 00000000*/ 0x55, //push ebp
/* 14 00000001*/ 0x89, 0xE5, //mov ebp, esp
/* 16 00000003*/ 0x83, 0xEC, 0x20, //sub esp, 32
/* 17 00000006*/ 0x8B, 0x45, 0x08, //mov eax, DWORD [ebp+8]
/* 18 00000009*/ 0x89, 0x45, 0xF8, //mov DWORD [ebp-8], eax
/* 19 0000000C*/ 0x81, 0x45, 0xF8, 0x00, 0x00, 0x01, 0x00, //add DWORD [ebp-8], 65536
/* 20 00000013*/ 0x8B, 0x45, 0xF8, //mov eax, DWORD [ebp-8]
/* 21 00000016*/ 0x89, 0x45, 0xF4, //mov DWORD [ebp-12], eax
/* 22 00000019*/ 0xC7, 0x45, 0xF0, 0xE8, 0x03, 0x00, 0x00, //mov DWORD [ebp-16], 1000
/* 23 00000020*/ 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, //mov DWORD [ebp-4], 0
/* 24 00000027*/ 0xEB, 0x37, //jmp L2
/* 26 00000029*/ 0x8B, 0x45, 0xFC, //mov eax, DWORD [ebp-4]
/* 27 0000002C*/ 0x8D, 0x14, 0xC5, 0x00, 0x00, 0x00, 0x00, //lea edx, [0+eax*8]
/* 28 00000033*/ 0x8B, 0x45, 0xF4, //mov eax, DWORD [ebp-12]
/* 29 00000036*/ 0x01, 0xD0, //add eax, edx
/* 30 00000038*/ 0x89, 0x45, 0xEC, //mov DWORD [ebp-20], eax
/* 31 0000003B*/ 0x8B, 0x45, 0xEC, //mov eax, DWORD [ebp-20]
/* 32 0000003E*/ 0x8B, 0x00, //mov eax, DWORD [eax]
/* 33 00000040*/ 0x89, 0xC2, //mov edx, eax
/* 34 00000042*/ 0x8B, 0x45, 0x08, //mov eax, DWORD [ebp+8]
/* 35 00000045*/ 0x01, 0xD0, //add eax, edx
/* 36 00000047*/ 0x89, 0x45, 0xE8, //mov DWORD [ebp-24], eax
/* 37 0000004A*/ 0x8B, 0x45, 0xEC, //mov eax, DWORD [ebp-20]
/* 38 0000004D*/ 0x8B, 0x40, 0x04, //mov eax, DWORD [eax+4]
/* 39 00000050*/ 0x89, 0xC2, //mov edx, eax
/* 40 00000052*/ 0x8B, 0x45, 0x08, //mov eax, DWORD [ebp+8]
/* 41 00000055*/ 0x01, 0xC2, //add edx, eax
/* 42 00000057*/ 0x8B, 0x45, 0xE8, //mov eax, DWORD [ebp-24]
/* 43 0000005A*/ 0x89, 0x10, //mov DWORD [eax], edx
/* 44 0000005C*/ 0x83, 0x45, 0xFC, 01, //add DWORD [ebp-4], 1
/* 46 00000060*/ 0x8B, 0x45, 0xFC, //mov eax, DWORD [ebp-4]
/* 47 00000063*/ 0x3B, 0x45, 0xF0, //cmp eax, DWORD [ebp-16]
/* 48 00000066*/ 0x7C, 0xC1, //jl L3
/* 49 00000068*/ 0xC9, //leave
/* 52 00000069*/ 0xC3 //ret
};
outputData.insert(outputData.end(), reallocationFunCode, reallocationFunCode + (sizeof(reallocationFunCode) / sizeof(uint8_t)));
int offsetPosInOutputData = startPos + 0xC + 3;
int numPosInOutputData = startPos + 0x19 + 3;
for (auto it = rellocations.begin(); it != rellocations.end(); )
{
if (it->type == 20)
{
int32_t off = it->offset;
int32_t symbol = it->symbol;
for (int i = 0; i < symbols.size(); i++)
{
auto &s = symbols[i];
if (s.COFFid >= 0 && symbol == s.COFFid)
{
int32_t target = s.pos;
//std::cout << COFFfile.getSymbolName(s.COFFid) << std::endl;
//std::cout << outputData[target] << std::endl;
//std::cout << off << std::endl;
target = target - (off + 4);
//std::cout << target << std::endl;
*reinterpret_cast<int32_t*>(std::addressof(outputData[it->offset])) = target;
break;
}
}
it = rellocations.erase(it);
}
else
{
auto &value = *reinterpret_cast<int32_t*>(std::addressof(outputData[it->offset]));
if (value > 0 && it->type == 6)
{
bool found = false;
for (int i = 0; i < COFFfile.getNumSymbols(); i++)
{
if (found)
break;
auto &symbol = COFFfile.symbolTable[i];
if (symbol.n_value == value)
{
for (int k = 0; k < symbols.size(); k++)
{
auto &s = symbols[k];
if (s.COFFid >= 0 && i == s.COFFid)
{
std::cout << "it symbol " << it->symbol << std::endl;
std::cout << "s.pos " << s.pos << std::endl;
/*std::cout << "COFFid " << i << std::endl;
std::cout << "it offset " << it->offset << std::endl;
std::cout << "name " << COFFfile.getSymbolName(i) << std::endl;
std::cout << "value " << value << std::endl;
std::cout << "symbol.n_numaux " << (int)symbol.n_numaux << std::endl;
std::cout << "symbol.n_sclass " << (int)symbol.n_sclass << std::endl;
std::cout << "symbol.n_scnum " << (int)symbol.n_scnum << std::endl;
std::cout << "symbol.n_type " << (int)symbol.n_type << std::endl;
std::cout << "symbol.n_value " << symbol.n_value << std::endl;
std::cout << "it section " << it->section << std::endl;*/
it->symbol = i;
it->type = 777;
value = s.pos;
//value = 0;
found = true;
break;
}
}
}
}
if (!found)
{
std::cout << "Symbol detect error " << it->offset << std::endl;
}
//value += 0x00400000;
}
else
{
//std::cout << "Other type? " << it->offset << " " << it->symbol << " " << it->type << " " << *reinterpret_cast<int32_t*>(std::addressof(outputData[it->offset])) << std::endl;
}
++it;
}
}
const int reallocationNum = rellocations.size();
const int reallocationOffset = outputData.size();
*reinterpret_cast<int32_t*>(&outputData[offsetPosInOutputData]) = reallocationOffset;
*reinterpret_cast<int32_t*>(&outputData[numPosInOutputData]) = reallocationNum;
{
for (auto &r : rellocations)
{
for (int i = 0; i < symbols.size(); i++)
{
auto &s = symbols[i];
if (s.COFFid >= 0 && s.COFFid == (r.symbol))
{
auto &symbol = COFFfile.symbolTable[s.COFFid];
if (r.type == 6)
{
//std::cout << COFFfile.getSymbolName(s.COFFid) << std::endl;
r.symbol = s.pos + *reinterpret_cast<int32_t*>(&outputData[r.offset]);
*reinterpret_cast<int32_t*>(&outputData[r.offset]) = r.symbol;
/*std::cout << "r.offset " << r.offset << std::endl;
std::cout << "r.symbol " << r.symbol << std::endl;
std::cout << "r.type " << r.type << std::endl;
std::cout << "*(int*)&outputData[r.offset] " << *(int*)&outputData[r.offset] << std::endl;*/
}
else
{
r.symbol = *reinterpret_cast<int32_t*>(&outputData[r.offset]);
}
}
}
}
uint8_t relocationTop[] = { 0x55, 0x89, 0xE5 };
uint8_t relocationMiddle[] = {
/* 16 00000003*/ 0x83, 0xEC, 0x10, //sub esp, 16
/* 17 00000006*/ 0xC7, 0x45, 0xFC, 0x30, 0x18, 0x20, 0x41, //mov DWORD [ebp-4], 1092622384
/* 18 0000000D*/ 0xC7, 0x45, 0xF8, 0x50, 0x31, 0x20, 0x51, //mov DWORD [ebp-8], 1361064272
/* 19 00000014*/ 0x8B, 0x55, 0xFC, //mov edx, DWORD [ebp-4]
/* 20 00000017*/ 0x8B, 0x45, 0x08, //mov eax, DWORD [ebp+8]
/* 21 0000001A*/ 0x01, 0xD0, //add eax, edx
/* 22 0000001C*/ 0x89, 0x45, 0xF4, //mov DWORD [ebp-12], eax
/* 23 0000001F*/ 0x8B, 0x55, 0xF8, //mov edx, DWORD [ebp-8]
/* 24 00000022*/ 0x8B, 0x45, 0x08, //mov eax, DWORD [ebp+8]
/* 25 00000025*/ 0x01, 0xC2, //add edx, eax
/* 26 00000027*/ 0x8B, 0x45, 0xF4, //mov eax, DWORD [ebp-12]
/* 27 0000002A*/ 0x89, 0x10 //mov DWORD [eax], edx
};
uint8_t relocationBtn[] = { 0xC9, 0xC3 };
/*outputData.insert(outputData.end(), relocationTop, relocationTop + (sizeof(relocationTop) / sizeof(uint8_t)));
for (auto &r : rellocations)
{
*reinterpret_cast<int32_t*>(std::addressof(relocationMiddle[3 + 3])) = r.offset;
*reinterpret_cast<int32_t*>(std::addressof(relocationMiddle[0xA + 3])) = r.symbol;
outputData.insert(outputData.end(), relocationMiddle, relocationMiddle + (sizeof(relocationMiddle) / sizeof(uint8_t)));
}
outputData.insert(outputData.end(), relocationBtn, relocationBtn + (sizeof(relocationBtn) / sizeof(uint8_t)));*/
}
if (reallocationNum > 0)
{
std::vector<reallocationTableToFile> rl;
rl.reserve(rellocations.size());
for (auto &r : rellocations)
{
rl.push_back(r);
}
uint8_t *r = reinterpret_cast<uint8_t*>(&rl[0]);
scriptSymbols ns;
ns.name = "relocationTable";
ns.pos = outputData.size();
symbols.push_back(std::move(ns));
outputData.insert(outputData.end(), r, r + (reallocationNum * sizeof(reallocationTableToFile)));
}
else
{
outputData.insert(outputData.end(), 12, 0u);
}
}
{
outputData.insert(outputData.end(), 8, 0x90);
scriptSymbols ns;
ns.name = "_initCPPCode";
ns.pos = outputData.size();
symbols.push_back(std::move(ns));
outputData.push_back(0x60); // pushad
outputData.push_back(0x9C); // pushfd
//outputData.push_back(0xCC);
makeCall(outputData, 0);
//outputData.push_back(0xCC);
outputData.push_back(0x50);
makeCall(outputData, reallocationFunctionPos);
uint8_t addesp4[] = { 0x83, 0xC4, 0x04 };
//outputData.push_back(0xCC);
outputData.insert(outputData.end(), addesp4, addesp4 + (sizeof(addesp4) / sizeof(uint8_t)));
try
{
auto &symbol = getSymbolByName(".ctors");
int num = *reinterpret_cast<int32_t*>(&outputData[symbol.pos]);
//std::cout << ".ctors: " << symbol.name << " " << symbol.COFFid << " " << symbol.pos << " " << num << std::endl;
bool callCreated = false;
for (int i = 0; i < symbols.size(); i++)
{
auto &s = symbols[i];
if (s.COFFid >= 0)
{
auto &symbol = COFFfile.symbolTable[s.COFFid];
if (symbol.n_value == num)
{
makeCall(outputData, s.pos);
callCreated = true;
break;
}
}
}
if (!callCreated)
{
std::cout << "Ctor found but not created the call, trying second method...\n";
for (int i = 0; i < symbols.size(); i++)
{
auto &s = symbols[i];
if (s.COFFid >= 0)
{
if (s.pos == num)
{
makeCall(outputData, s.pos);
callCreated = true;
break;
}
}
}
if (callCreated)
{
std::cout << "Call to ctor created\n";
}
else
{
std::cout << "Fail to search ctor function symbol\n";
}
}
}
catch (const std::exception &e)
{
std::cout << "Erro ao detectar o construtor\n" << e.what() << std::endl;
for (int i = 0; i < COFFfile.getNumSymbols(); i++)
{
std::cout << COFFfile.getSymbolName(i) << std::endl;
}
std::cout << "Talvez algo tenha dado errado, por favor avise no tópico: http://brmodstudio.forumeiros.com/t6959-" << std::endl;
std::cout << "Talvez algo tenha dado errado, por favor avise no tópico: http://brmodstudio.forumeiros.com/t6959-" << std::endl;
std::cout << "Talvez algo tenha dado errado, por favor avise no tópico: http://brmodstudio.forumeiros.com/t6959-" << std::endl;
}
outputData.push_back(0x9D); // popfd
outputData.push_back(0x61); // popad
outputData.push_back(0xC3); // InitCPPCode ret
}
if (rellocOffset > 0)
{
for (auto &r : rellocations)
{
*reinterpret_cast<int32_t*>(&outputData[r.offset]) = r.symbol + rellocOffset;
}
}
{
std::fstream rawFile(outFinalFile + ".raw", std::ios::out | std::ios::trunc | std::ios::binary);
rawFile.write(reinterpret_cast<const char*>(outputData.data()), outputData.size());
}
std::wcout << L"Bytes de código " << outputData.size() << std::endl;
vectorDataToFile(COFFfile, fout, outputData);
}
}
}
int main()
{
loadSymbolList();
try {
CText Config("Config.txt");
compileCMD = Config[""]["compileCMD"];
compileCMD2 = Config[""]["compileCMD2"];
}
catch (const std::exception &e) {
MessageBoxA(0, e.what(), "Error", 0);
return 0;
}
bool what = true, doExit = false;
int wopt = 0;
int estagMenu = 0;
std::cout << "**** ESTE PROGRAMA ESTÁ EM FASE DE CRIAÇÃO E TESTES - USE POR SUA CONTA E RISCO ****" << std::endl;
std::cout << "**** ESTE PROGRAMA ESTÁ EM FASE DE CRIAÇÃO E TESTES - USE POR SUA CONTA E RISCO ****" << std::endl;
std::cout << "**** ESTE PROGRAMA ESTÁ EM FASE DE CRIAÇÃO E TESTES - USE POR SUA CONTA E RISCO ****" << std::endl;
std::cout << "*******************************************************************************************************************" << std::endl;
std::cout << "Em caso de duvida entre em contato pelo seguinte topico:" << std::endl;
std::cout << "http://brmodstudio.forumeiros.com/t4721-avancado-facilitador-de-conversao-de-c-para-assembly-para-usar-em-scripts-cleo-scm" << std::endl << std::endl;
std::cout << "http://brmodstudio.forumeiros.com/t6996-" << std::endl << std::endl;
std::cout << "Programa por Fabio Rossini Sluzala" << std::endl;
std::cout << "Obrigado a todas as pessoas que contribuiram para que essa ideia se tornasse possivel" << std::endl;
std::cout << "Brazilian Modding Studio" << std::endl;
std::cout << "*******************************************************************************************************************" << std::endl;
std::cout << std::endl;
std::string infile = "new.cpp", outCompilefile = "new.o", outFinalFile = "out.txt";
std::string optTemp;
do
{
switch (estagMenu)
{
case 0:
what = true;
do
{
std::wcout << L"Usando modo " << (outputToGTA3SCFormat? "GTA3Script" : "Sanny Builder") << "\n";
std::wcout << L"Opções:\n";
std::wcout << L" 1. Compilar source C/C++ e gerar código CLEO/SCM\n";
std::wcout << L" 2. Gerar código para CLEO/SCM de um objeto pronto\n";
std::wcout << L" 3. Usar sintaxe de Sanny Builder\n";
std::wcout << L" 4. Usar sintaxe de GTA3Script\n";
std::wcout << L" 5. Sair\n";
optTemp = "";
std::cin >> optTemp;
try
{
wopt = std::stoi(optTemp);
switch (wopt)
{
case 1:
++estagMenu;
what = false;
break;
case 2:
++estagMenu;
what = false;
break;
case 3:
outputToGTA3SCFormat = false;
break;
case 4:
outputToGTA3SCFormat = true;
break;
case 5:
what = false;
return 0;
break;
default:
std::wcout << L"Opção inválida, selecione uma opção de 1 a 3\n\n";
break;
}
}
catch (const std::exception &e)
{
std::cout << e.what() << std::endl;
}
} while (what);
break;
case 1:
{
what = true;
do
{
switch (wopt)
{
case 1:
{
std::wcout << L"Digite o nome do arquivo a ser compilado:\n";
optTemp = "";
std::cin >> optTemp;
if (optTemp.size() > 0)
{
infile = optTemp;
++estagMenu;
what = false;
}
}
break;
case 2:
{
std::wcout << L"Digite o nome do objeto (arquivo do tipo COFF) a ser convertido para uso em Scripts CLEO/SCM:\n";
optTemp = "";
std::cin >> optTemp;
if (optTemp.size() > 0)
{
outCompilefile = optTemp;
estagMenu += 2;
what = false;
}
}
break;
default:
std::wcout << L"Erro, opcao invalida\n";
estagMenu = 0;
what = false;
break;
}
} while (what);
break;
}
case 2:
{
what = true;
do
{
std::wcout << L"Digite o nome do arquivo intermediario (COFF object file):\n";
optTemp = "";
std::cin >> optTemp;
if (optTemp.size() > 0)
{
outCompilefile = optTemp;
++estagMenu;
what = false;
}
} while (what);
}
case 3:
{
what = true;
do
{
std::wcout << L"Digite o nome do arquivo de saída final:\n";
optTemp = "";
std::cin >> optTemp;
if (optTemp.size() > 0)
{
outFinalFile = optTemp;
++estagMenu;
what = false;
}
} while (what);
if (wopt == 1)
{
std::string commandToRun = multiRegister(compileCMD, infile, outCompilefile);
std::cout << "Rodando o seguinte comando...\n";
std::cout << commandToRun << std::endl;
executeCommand(commandToRun);
}
COFFFile COFFfile = openCOFFFile(outCompilefile);
toCLEOSCM(COFFfile, outFinalFile);
std::cout << "Comandos terminados, voltando ao inicio do menu...\n\n\n";
estagMenu = 0;
}
break;
}
} while (!doExit);
system("pause");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment