WIP: Added Configuration, allow value modification and patching settings based on those
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
fbc5c63a47
commit
38f0b983b6
|
@ -26,3 +26,149 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "Configuration.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
bool Configuration::addEntry(const std::string &entry) {
|
||||
if(entry.empty() || entry[0] == '#'){
|
||||
return false;
|
||||
}
|
||||
std::string currentKey;
|
||||
currentKey.reserve(16);
|
||||
|
||||
uint32_t state = 0;
|
||||
|
||||
ConfigurationNode* currentNode = &mainNode;
|
||||
|
||||
for(size_t i = 0; i < entry.size(); ++i){
|
||||
auto c = entry[i];
|
||||
if(state == 0){
|
||||
if((c == '.' || c == ' ' || c == '\t')){
|
||||
if(!currentKey.empty()){
|
||||
currentNode = ¤tNode->getOrCreateSubNode(currentKey);
|
||||
|
||||
currentKey.clear();
|
||||
|
||||
if(c == ' ' || c == '\t'){
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
currentKey += c;
|
||||
}
|
||||
} else if(state == 1){
|
||||
if((c == ' ' || c == '\t')){
|
||||
if(!currentKey.empty()){
|
||||
if(currentKey == "int"){
|
||||
currentNode->type = ConfigurationNode::Type::ValueInt;
|
||||
}else if(currentKey == "text"){
|
||||
currentNode->type = ConfigurationNode::Type::ValueText;
|
||||
}else if(currentKey == "bool"){
|
||||
currentNode->type = ConfigurationNode::Type::ValueBool;
|
||||
}
|
||||
|
||||
currentKey.clear();
|
||||
|
||||
state = 2;
|
||||
}
|
||||
}else{
|
||||
currentKey += c;
|
||||
}
|
||||
} else if(state == 2){
|
||||
if(i == (entry.size() - 1)){
|
||||
currentKey += c;
|
||||
currentNode->value = currentKey;
|
||||
}else if((c == ' ' || c == '\t') && currentKey.empty()){
|
||||
|
||||
} else {
|
||||
currentKey += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state == 2;
|
||||
}
|
||||
|
||||
const Configuration::ConfigurationNode &Configuration::getEntry(const std::string &entry) const {
|
||||
if(entry.empty() || entry[0] == '#'){
|
||||
return mainNode;
|
||||
}
|
||||
std::string currentKey;
|
||||
currentKey.reserve(16);
|
||||
|
||||
const ConfigurationNode* currentNode = &mainNode;
|
||||
|
||||
for(char c : entry){
|
||||
if((c == '.' || c == ' ' || c == '\t')){
|
||||
if(!currentKey.empty()){
|
||||
currentNode = currentNode->getSubNode(currentKey);
|
||||
|
||||
if(currentNode == nullptr){
|
||||
return mainNode;
|
||||
}
|
||||
|
||||
currentKey.clear();
|
||||
|
||||
if(c == ' ' || c == '\t'){
|
||||
return *currentNode;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
currentKey += c;
|
||||
}
|
||||
}
|
||||
|
||||
if(!currentKey.empty()) {
|
||||
currentNode = currentNode->getSubNode(currentKey);
|
||||
if(currentNode != nullptr){
|
||||
return *currentNode;
|
||||
}
|
||||
}
|
||||
|
||||
return mainNode;
|
||||
}
|
||||
|
||||
void Configuration::getAllEntriesForNode(std::vector<std::string> &entries, const Configuration::ConfigurationNode &node, const std::string &key) const {
|
||||
for(const auto& n : node.possibleNodes){
|
||||
if(n.type != ConfigurationNode::Type::Node){
|
||||
entries.push_back(key + n.name + " " + n.getTypeString() + " " + n.value);
|
||||
}else{
|
||||
getAllEntriesForNode(entries, n, key + n.name + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Configuration::getAllEntries() const {
|
||||
std::vector<std::string> entries;
|
||||
|
||||
for(const auto& n : mainNode.possibleNodes){
|
||||
if(n.type == ConfigurationNode::Type::Node){
|
||||
getAllEntriesForNode(entries, n, n.name + ".");
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(entries.begin(), entries.end());
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
Configuration::ConfigurationNode &Configuration::ConfigurationNode::getOrCreateSubNode(const std::string &k) {
|
||||
for (auto& node : possibleNodes){
|
||||
if(node.name == k){
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
possibleNodes.emplace_back(ConfigurationNode(k, ConfigurationNode::Type::Node));
|
||||
return possibleNodes[possibleNodes.size() - 1];
|
||||
}
|
||||
|
||||
const Configuration::ConfigurationNode *Configuration::ConfigurationNode::getSubNode(const std::string &k) const {
|
||||
for (auto& node : possibleNodes){
|
||||
if(node.name == k){
|
||||
return &node;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -28,10 +28,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
class Configuration {
|
||||
public:
|
||||
|
@ -61,39 +58,24 @@ public:
|
|||
std::string getTypeString() const{
|
||||
switch (type) {
|
||||
case Type::Node:
|
||||
return "";
|
||||
return "node";
|
||||
case Type::ValueText:
|
||||
return "text";
|
||||
case Type::ValueInt:
|
||||
return "int";
|
||||
case Type::ValueBool:
|
||||
return "bool";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
const ConfigurationNode* getSubNode(const std::string& k) const{
|
||||
for (auto& node : possibleNodes){
|
||||
if(node.name == k){
|
||||
return &node;
|
||||
}
|
||||
}
|
||||
const ConfigurationNode* getSubNode(const std::string& k) const;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConfigurationNode& getOrCreateSubNode(const std::string& k){
|
||||
for (auto& node : possibleNodes){
|
||||
if(node.name == k){
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
possibleNodes.emplace_back(ConfigurationNode(k, ConfigurationNode::Type::Node));
|
||||
return possibleNodes[possibleNodes.size() - 1];
|
||||
}
|
||||
ConfigurationNode& getOrCreateSubNode(const std::string& k);
|
||||
|
||||
bool getBool() const{
|
||||
return value == "true";
|
||||
return value == "true" || value == "1";
|
||||
}
|
||||
|
||||
int getInteger() const{
|
||||
|
@ -107,120 +89,12 @@ public:
|
|||
|
||||
ConfigurationNode mainNode = ConfigurationNode("");
|
||||
|
||||
std::vector<std::string> getAllEntries() const{
|
||||
std::vector<std::string> entries;
|
||||
std::vector<std::string> getAllEntries() const;
|
||||
|
||||
for(const auto& n : mainNode.possibleNodes){
|
||||
if(n.type == ConfigurationNode::Type::Node){
|
||||
getAllEntriesForNode(entries, n, n.name + ".");
|
||||
}
|
||||
}
|
||||
void getAllEntriesForNode(std::vector<std::string>& entries, const ConfigurationNode& node, const std::string& key) const;
|
||||
|
||||
std::sort(entries.begin(), entries.end());
|
||||
const ConfigurationNode& getEntry(const std::string& entry) const;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
void getAllEntriesForNode(std::vector<std::string>& entries, const ConfigurationNode& node, const std::string& key) const{
|
||||
for(const auto& n : node.possibleNodes){
|
||||
if(n.type != ConfigurationNode::Type::Node){
|
||||
entries.push_back(key + n.name + " " + n.getTypeString() + " " + n.value);
|
||||
}else{
|
||||
getAllEntriesForNode(entries, n, key + n.name + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ConfigurationNode& getEntry(const std::string& entry) const{
|
||||
if(entry.empty() || entry[0] == '#'){
|
||||
return mainNode;
|
||||
}
|
||||
std::string currentKey;
|
||||
currentKey.reserve(16);
|
||||
|
||||
const ConfigurationNode* currentNode = &mainNode;
|
||||
|
||||
for(char c : entry){
|
||||
if((c == '.' || c == ' ' || c == '\t')){
|
||||
if(!currentKey.empty()){
|
||||
currentNode = currentNode->getSubNode(currentKey);
|
||||
|
||||
if(currentNode == nullptr){
|
||||
return mainNode;
|
||||
}
|
||||
|
||||
currentKey.clear();
|
||||
|
||||
if(c == ' ' || c == '\t'){
|
||||
return *currentNode;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
currentKey += c;
|
||||
}
|
||||
}
|
||||
|
||||
return mainNode;
|
||||
}
|
||||
|
||||
bool addEntry(const std::string& entry){
|
||||
if(entry.empty() || entry[0] == '#'){
|
||||
return false;
|
||||
}
|
||||
std::string currentKey;
|
||||
currentKey.reserve(16);
|
||||
|
||||
uint32_t state = 0;
|
||||
|
||||
ConfigurationNode* currentNode = &mainNode;
|
||||
|
||||
for(size_t i = 0; i < entry.size(); ++i){
|
||||
auto c = entry[i];
|
||||
if(state == 0){
|
||||
if((c == '.' || c == ' ' || c == '\t')){
|
||||
if(!currentKey.empty()){
|
||||
currentNode = ¤tNode->getOrCreateSubNode(currentKey);
|
||||
|
||||
currentKey.clear();
|
||||
|
||||
if(c == ' ' || c == '\t'){
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
currentKey += c;
|
||||
}
|
||||
} else if(state == 1){
|
||||
if((c == ' ' || c == '\t')){
|
||||
if(!currentKey.empty()){
|
||||
if(currentKey == "int"){
|
||||
currentNode->type = ConfigurationNode::Type::ValueInt;
|
||||
}else if(currentKey == "text"){
|
||||
currentNode->type = ConfigurationNode::Type::ValueText;
|
||||
}else if(currentKey == "bool"){
|
||||
currentNode->type = ConfigurationNode::Type::ValueBool;
|
||||
}
|
||||
|
||||
currentKey.clear();
|
||||
|
||||
state = 2;
|
||||
}
|
||||
}else{
|
||||
currentKey += c;
|
||||
}
|
||||
} else if(state == 2){
|
||||
if(i == (entry.size() - 1)){
|
||||
currentKey += c;
|
||||
currentNode->value = currentKey;
|
||||
}else if((c == ' ' || c == '\t') && currentKey.empty()){
|
||||
|
||||
} else {
|
||||
currentKey += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state == 2;
|
||||
}
|
||||
bool addEntry(const std::string& entry);
|
||||
|
||||
};
|
|
@ -35,7 +35,7 @@
|
|||
#include "Registers.h"
|
||||
#include "instructions/Write.h"
|
||||
|
||||
const std::unique_ptr<Instruction::Instruction> ImageFormat::NULL_INSTRUCTION(nullptr);
|
||||
std::unique_ptr<Instruction::Instruction> ImageFormat::NULL_INSTRUCTION(nullptr);
|
||||
|
||||
ImageFormat ImageFormat::fromBytes(const std::vector<uint8_t>& imageBytes) {
|
||||
ImageFormat image;
|
||||
|
@ -119,7 +119,7 @@ ImageFormat ImageFormat::fromBytes(const std::vector<uint8_t>& imageBytes) {
|
|||
|
||||
std::vector<uint8_t> ImageFormat::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
bytes.resize(baseImage.size(), 0xFF);
|
||||
bytes.resize(baseImage.size() - 1, 0xFF);
|
||||
|
||||
uint32_t offset = 0;
|
||||
|
||||
|
|
|
@ -63,13 +63,13 @@ public:
|
|||
|
||||
void decodeAnalyzeInstructionsAt(uint32_t offset);
|
||||
|
||||
const std::unique_ptr<Instruction::Instruction>& findInstructionByAddress(uint32_t addr, bool indirect = false){
|
||||
std::unique_ptr<Instruction::Instruction>& findInstructionByAddress(uint32_t addr, bool indirect = false){
|
||||
if(instructions.find(addr) != instructions.end()){
|
||||
return instructions.find(addr)->second;
|
||||
}
|
||||
|
||||
if(indirect){
|
||||
for(const auto& instruction : instructions){
|
||||
for(auto& instruction : instructions){
|
||||
if(
|
||||
(instruction.second->getEndAddress() == 0 && addr == instruction.second->getAddress())
|
||||
|| (
|
||||
|
@ -106,8 +106,14 @@ public:
|
|||
return bootConfig;
|
||||
}
|
||||
|
||||
auto& getModifiableBootConfig(){
|
||||
return bootConfig;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> toBytes() const;
|
||||
|
||||
std::string imageSignature;
|
||||
|
||||
private:
|
||||
|
||||
struct {
|
||||
|
@ -121,7 +127,7 @@ private:
|
|||
static const int CFG_HEADER = 16;
|
||||
static const int CFG_LENGTH = 16;
|
||||
|
||||
static const std::unique_ptr<Instruction::Instruction> NULL_INSTRUCTION;
|
||||
static std::unique_ptr<Instruction::Instruction> NULL_INSTRUCTION;
|
||||
|
||||
struct {
|
||||
uint8_t length : 8;
|
||||
|
@ -139,6 +145,4 @@ private:
|
|||
std::map<uint32_t, std::unique_ptr<Instruction::Instruction>> instructions;
|
||||
|
||||
std::vector<uint8_t> baseImage;
|
||||
|
||||
std::string imageSignature;
|
||||
};
|
|
@ -176,4 +176,8 @@ std::string getAddressRegisterName(uint32_t addr, uint8_t offset){
|
|||
s << getRegisterName(static_cast<KnownRegisters>(addr));
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
KnownRegisters getScratchRegister(uint32_t offset){
|
||||
return static_cast<KnownRegisters>((uint32_t)KnownRegisters::BSM_SCRATCH_START + offset);
|
||||
}
|
|
@ -120,6 +120,8 @@ enum class KnownRegisters : uint32_t {
|
|||
NOP = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
KnownRegisters getScratchRegister(uint32_t offset);
|
||||
|
||||
std::string getRegisterName(KnownRegisters addr);
|
||||
|
||||
std::string getAddressRegisterName(uint32_t addr, uint8_t offset = 0);
|
|
@ -30,7 +30,11 @@
|
|||
void Instruction::End::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
||||
offset += 4;
|
||||
offset++;
|
||||
|
||||
reserved = bytes[offset++] << 16;
|
||||
reserved |= bytes[offset++] << 8;
|
||||
reserved |= bytes[offset++];
|
||||
|
||||
_endAddress = offset;
|
||||
}
|
||||
|
@ -54,9 +58,9 @@ std::vector<uint8_t> Instruction::End::toBytes() const {
|
|||
|
||||
bytes.emplace_back((uint8_t)getCommand());
|
||||
|
||||
bytes.emplace_back(0xFF);
|
||||
bytes.emplace_back(0xFF);
|
||||
bytes.emplace_back(0xFF);
|
||||
bytes.emplace_back((reserved >> 16) & 0xFF);
|
||||
bytes.emplace_back((reserved >> 8) & 0xFF);
|
||||
bytes.emplace_back(reserved & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
|
|
@ -50,5 +50,6 @@ namespace Instruction{
|
|||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> execute(AnalysisState& state) const override;
|
||||
|
||||
uint32_t reserved = 0;
|
||||
};
|
||||
}
|
66
src/main.cpp
66
src/main.cpp
|
@ -32,6 +32,8 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "ImageFormat.h"
|
||||
#include "Registers.h"
|
||||
#include "instructions/Load.h"
|
||||
|
||||
void decodeImage(const std::string& fileName){
|
||||
|
||||
|
@ -79,7 +81,7 @@ void decodeImage(const std::string& fileName){
|
|||
}
|
||||
}
|
||||
|
||||
void patchImage(const std::string& originalImage, const std::string& settings, const std::string& patchedImageFile){
|
||||
void patchImage(const std::string& originalImage, const std::string& settingsFile, const std::string& patchedImageFile){
|
||||
std::ifstream image(originalImage);
|
||||
if(image.is_open()) {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
@ -88,15 +90,63 @@ void patchImage(const std::string& originalImage, const std::string& settings, c
|
|||
}
|
||||
auto imageObject = ImageFormat::fromBytes(bytes);
|
||||
|
||||
//Do patch
|
||||
std::ifstream settings(settingsFile);
|
||||
if(settings.is_open()) {
|
||||
Configuration config;
|
||||
|
||||
std::string line;
|
||||
while (!settings.eof()) {
|
||||
std::getline(settings, line);
|
||||
config.addEntry(line);
|
||||
imageObject.getModifiableBootConfig().addEntry(line);
|
||||
}
|
||||
|
||||
//Do patch
|
||||
|
||||
if(imageObject.imageSignature.find("Image Generated with rrcBig_02.22. EEPROM Image Version: 0x0222 PCIe Master SPICO FW Version: 0x10130001 PCIe SerDes SPICO FW Version: 0x30550043") == std::string::npos){
|
||||
std::cout << "Could not find supported generation signature on original image. Patching will not proceed.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if(imageObject.imageSignature.find("rrcSmall") == std::string::npos){
|
||||
imageObject.imageSignature += " :: Patched by rrcSmall :: git.gammaspectra.live/FM10K/rrcSmall";
|
||||
}
|
||||
|
||||
auto baseOffsets = std::vector<uint32_t>{imageObject.getHeader().baseAddress, (uint32_t) imageObject.getHeader().baseAddress + 0x40000};
|
||||
|
||||
{
|
||||
auto entry = config.getEntry("api.platform.config.switch.0.bootCfg.mgmtPep");
|
||||
if(entry.type == Configuration::ConfigurationNode::Type::ValueInt && !entry.value.empty()){
|
||||
auto value = entry.getInteger();
|
||||
for(auto baseOffset : baseOffsets){
|
||||
auto& instruction = imageObject.findInstructionByAddress(baseOffset + 0x91f0);
|
||||
if(instruction != nullptr && instruction->getCommand() == Instruction::Instruction::CommandOp::LOAD){
|
||||
auto& load = reinterpret_cast<std::unique_ptr<Instruction::Load>&>(instruction);
|
||||
if(load->address == (uint32_t)getScratchRegister(0x02e) && load->data.size() == 9){
|
||||
for(uint32_t pepOffset = 0; pepOffset < 9; ++pepOffset){
|
||||
load->data[pepOffset] = pepOffset == value || value == -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream patchedImage(patchedImageFile);
|
||||
|
||||
if(patchedImage.is_open()) {
|
||||
auto result = imageObject.toBytes();
|
||||
for (auto c : result) {
|
||||
patchedImage.put(c);
|
||||
}
|
||||
patchedImage.close();
|
||||
settings.close();
|
||||
image.close();
|
||||
}
|
||||
|
||||
|
||||
std::ofstream patchedImage(patchedImageFile);
|
||||
auto result = imageObject.toBytes();
|
||||
for (auto c : result) {
|
||||
patchedImage.put(c);
|
||||
}
|
||||
patchedImage.close();
|
||||
image.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue