WIP: Added Configuration, allow value modification and patching settings based on those
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2020-12-22 08:14:35 +01:00
parent fbc5c63a47
commit 38f0b983b6
9 changed files with 240 additions and 155 deletions

View file

@ -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 = &currentNode->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;
}

View file

@ -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 = &currentNode->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);
};

View file

@ -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;

View file

@ -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;
};

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
};
}

View file

@ -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();
}
}