I want to replace couple bytes in binary file. But i am getting hard when i try to create an algoritm.
What i thought ?
Reading file with fstream, seaking the offset, replacing bytes and saving file.
But the issue starting here, i dont know how to find correct offset for my pattern of bytes.
For example i want to change:
0x70, 0x74, 0xFF, 0xFF
to
0x50, 0x50, 0x50, 0xFF
How can i find my pattern correctly and replace it with requested bytes?
CodePudding user response:
There basically 2 potential solutions:
- Read the complete file, modify the data in memory and rewrite the file
- Read byte by byte and compare on byte level. Work with file pointers. Rewrite only needed bytes.
Approach 1 runs faster and is easy to implement. However, it may need a lot of memory.
Solution 2 is very slow, but the memory footprint is low.
Please see below both solutions. Please note: There are many many other potential solutions.
Solution 1:
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>
#include <iterator>
std::vector<char> toSearch{'\x70','\x74', '\xff', '\xff' };
std::vector<char> newData{ '\x50','\x50', '\x50', '\xff' };
const std::string fileName{ "binary.exe" };
// Write some test data into a file
void writeTestFile() {
// Open file for writing
if (std::ofstream ofs{ fileName, std::ios::binary }; ofs) {
// Write something
for (unsigned char c{}; c < 128; c) ofs << c;
// Write data to search for
for (const unsigned char c : toSearch) ofs << c;
// Write something
for (unsigned char c{}; c < 128; c) ofs << c;
}
else std::cerr << "\nError: Could not open file '" << fileName << "' for writing\n\n";
}
int main() {
// Write a test file
writeTestFile();
// Open the file and check, if it could be opened
if (std::ifstream ifs{ fileName, std::ios::binary }; ifs) {
// Read the complete file into a vector
std::vector data(std::istreambuf_iterator<char>(ifs), {});
// Input File no longer needed
ifs.close();
// Search for the given data
auto position = std::search(data.begin(), data.end(), toSearch.begin(), toSearch.end());
// If we found something, then
if (position != data.end()) {
// Write the replacement data
std::copy(newData.begin(), newData.end(), position);
// And write data to back to file
if (std::ofstream ofs{ "r:\\binary.exe", std::ios::binary }; ofs) {
std::copy(data.begin(), data.end(), std::ostreambuf_iterator<char>(ofs));
std::cout << "\n\nReplacement done\n";
}
else std::cerr << "\nError: Could not open file '" << fileName << "' for writing\n\n";
}
else std::cout << "\n\nCould not find search string\n";
}
else std::cerr << "\nError: Could not open file '" << fileName << "' for reading\n\n";
}
Solution 2
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>
#include <iterator>
std::vector<char> toSearch{ '\x70','\x74', '\xff', '\xff' };
std::vector<char> newData{ '\x50','\x50', '\x50', '\xff' };
const std::string fileName{ "binary.exe" };
// Write some test data into a file
void writeTestFile() {
// Open file for writing
if (std::ofstream ofs{ fileName, std::ios::binary }; ofs) {
// Write something
for (unsigned char c{}; c < 240; c) ofs << c;
// Write data to search for
for (const unsigned char c : toSearch) ofs << c;
// Write something
for (unsigned char c{}; c < 240; c) ofs << c;
}
else std::cerr << "\nError: Could not open file '" << fileName << "' for writing\n\n";
}
int main() {
// Write a test file
writeTestFile();
// Open the file and check, if it could be opened
if (std::fstream fs{ fileName, std::ios::binary |std::ios::in |std::ios::out }; fs) {
// Read byte by byte which will be really slow
for (char c{}; fs.get(c); ) {
// Check if we read a charcater that matches the first character of the search string
if (c == toSearch.front()) {
// Remember the current position of the read file pointer (it is now one after the read character)
std::streamoff position = fs.tellg();
// Not try to match the rest of the serach string
bool match{ true };
// Go through the rest of the charcaters in the search data
for (size_t i{ 1 }; i < toSearch.size(); i)
// Read next byte and compare
if (fs.get(c) and c != toSearch[i]) {
// If there is a mistmatch, then stop reading and comparing
match = false;
break;
}
// If there was a complete match
if (match) {
// Set the write pointer to the begin of the matching bytes
fs.seekp(position - 1);
// Write the new data
std::copy(newData.begin(), newData.end(), std::ostreambuf_iterator<char>(fs));
fs.flush();
}
// No, replacement done or not, set read pointer back to original position
fs.seekg(position);
}
}
}
else std::cerr << "\nError: Could not open file '" << fileName << "'\n\n";
}
CodePudding user response:
Armin's solutions seems pretty clear, but if i understand you right you will need to search for code pattern scan. Because couple bytes will be change for the file.
Code pattern example: /x70/x90/x00/x00/x75/x44/ -> xx??xx
Check the following function:
char* ScanBasic(char* pattern, char* mask, char* begin, intptr_t size)
{
intptr_t patternLen = strlen(mask);
for (int i = 0; i < size; i )
{
bool found = true;
for (int j = 0; j < patternLen; j )
{
if (mask[j] != '?' && pattern[j] != *(char*)((intptr_t)begin i j))
{
found = false;
break;
}
}
if (found)
{
return (begin i);
}
}
return nullptr;
}