Home > Back-end >  pattern replace on binary file
pattern replace on binary file

Time:10-06

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:

  1. Read the complete file, modify the data in memory and rewrite the file
  2. 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;
}
  •  Tags:  
  • c
  • Related