从 exe 的 .data 和 .rdata 读取值。字节对齐
Reading values from .data and .rdata of exe. Bytes alignment
我有一个从这段代码编译的非常小的 exe(调试,未优化):
struct some_data
{
unsigned long long a;
unsigned long long b;
}
int main ()
{
constexpr some_data {0x1234567890abcdef, 0xabcdabcdabcdabcd}
cout << some_data.a << endl;
return 0;
}
现在我想制作另一个程序,在第一个 exe 中找到值 0x1234567890abcdef 并将其替换为 0x111111111111111 然后保存 exe,所以下次我 运行 我得到 "injected" 0x111111111111111作为输出。
我制作了一个简单的程序,可以按照以下方式执行某些操作:
uint64_t key = 0x1234567890abcdef;
uint64_t value;
fstream file ("file", ios::in| ios::out | ios::binary);
if (file.is_open())
{
while (not_end_of_file) {
file.read (&value, sizeof(value));
if (value == key) {
//code that overwrittes the old value with new
}
}
它确实工作了一两次让我很高兴,但是在我向第一个项目添加一些代码并重建它之后,替换(第二个项目)突然停止工作。在停止输入代码的 if (value == key) 部分。我认为发生这种情况的原因是在添加一些代码后,.data 部分中的结构在文件中向前移动了几个字节,现在当读取 8 字节的块时,它不再像这样在一个块中(little_endianess)
XX XX XX ef cd ab 90 78 one read operation
56 34 12 XX XX XX XX XX the next read operation
你觉得是这样吗?我可以期望 .data 和 .rdata 部分以任何可靠的方式对齐吗?您将如何实施将这种转变考虑在内的检查?或者,也许有人对如何轻松地以编程方式更改此值有完全不同的想法。
此致
马辛
看来您不能依赖数据对齐,或者至少不能像我以前那样依赖。
注意 如果您想复制实现,您最好使用 取消引用者的答案 中的代码,因为它更清晰。我留下了关于数据对齐的信息和实现它的替代方法的答案。
这是我想出的代码,它逐个加载字节并检查最后 8 个字节。这是为了小端,对于大我相信你需要改变字节是 "value" 引用,并改变移位方向。
#include <iostream>
#include <fstream>
using namespace std;
using magic_bytes_t = uint64_t;
const magic_bytes_t search_key{ 0x1234567890abcdef };
const magic_bytes_t replacemenet_key{ 0x1212121212121212 };
struct data_struct
{
const magic_bytes_t value_to_replace;
};
union parsing_union
{
magic_bytes_t value;
uint8_t bytes[sizeof(magic_bytes_t)];
};
int main()
{
std::fstream myFile("C:\Users\crazy_path\x64\Debug\SampleApplication.exe", ios::in | ios::out | ios::binary);
if (!myFile) {
cout << "Couldn't open file" << endl;
return EXIT_FAILURE;
} else {
parsing_union parsing_helper{ 0x0000000000000000 };
uint8_t &single_byte_value = parsing_helper.bytes[7];
while (myFile.read((char*)&single_byte_value, sizeof(single_byte_value)))
{
if (parsing_helper.value == search_key)
{
uint64_t control_key_start_position = myFile.tellg();
control_key_start_position -= sizeof(parsing_helper.value);
myFile.seekp(control_key_start_position);
myFile.write(reinterpret_cast<const char*>(&replacemenet_key), sizeof(replacemenet_key));
cout << "GOT EM !! GOT EM GOOD" << endl;;
break;
} else {
parsing_helper.value >>= (sizeof(single_byte_value) * 8);
}
}
}
system("pause");
return EXIT_SUCCESS;
}
这可能看起来有点贫民窟,但您可以将整个文件加载到字节数组中,然后将字节取消引用到 uint64_t,如下所示:
(是的,抱歉,我没有包含完整的代码,但这应该会给你一个 idea/be 清楚)
byte* bytes = new byte[filesizeinbytes];
//read to the byte array
then:
DWORD offset = 0;
while( *(uint64_t*)((DWORD)bytes+offset) != 0x1234567890abcdef )
{
offset++;
}
//We found the right address, so we can replace the bytes/address/offset
*(uint64_t*)((DWORD)bytes+offset) = 0x111111111111111;
//write the entire file, starting from bytes till the end of the file
delete[] bytes; // free the allocated memory
bytes = 0;
我有一个从这段代码编译的非常小的 exe(调试,未优化):
struct some_data
{
unsigned long long a;
unsigned long long b;
}
int main ()
{
constexpr some_data {0x1234567890abcdef, 0xabcdabcdabcdabcd}
cout << some_data.a << endl;
return 0;
}
现在我想制作另一个程序,在第一个 exe 中找到值 0x1234567890abcdef 并将其替换为 0x111111111111111 然后保存 exe,所以下次我 运行 我得到 "injected" 0x111111111111111作为输出。
我制作了一个简单的程序,可以按照以下方式执行某些操作:
uint64_t key = 0x1234567890abcdef;
uint64_t value;
fstream file ("file", ios::in| ios::out | ios::binary);
if (file.is_open())
{
while (not_end_of_file) {
file.read (&value, sizeof(value));
if (value == key) {
//code that overwrittes the old value with new
}
}
它确实工作了一两次让我很高兴,但是在我向第一个项目添加一些代码并重建它之后,替换(第二个项目)突然停止工作。在停止输入代码的 if (value == key) 部分。我认为发生这种情况的原因是在添加一些代码后,.data 部分中的结构在文件中向前移动了几个字节,现在当读取 8 字节的块时,它不再像这样在一个块中(little_endianess)
XX XX XX ef cd ab 90 78 one read operation
56 34 12 XX XX XX XX XX the next read operation
你觉得是这样吗?我可以期望 .data 和 .rdata 部分以任何可靠的方式对齐吗?您将如何实施将这种转变考虑在内的检查?或者,也许有人对如何轻松地以编程方式更改此值有完全不同的想法。
此致 马辛
看来您不能依赖数据对齐,或者至少不能像我以前那样依赖。
注意 如果您想复制实现,您最好使用 取消引用者的答案 中的代码,因为它更清晰。我留下了关于数据对齐的信息和实现它的替代方法的答案。
这是我想出的代码,它逐个加载字节并检查最后 8 个字节。这是为了小端,对于大我相信你需要改变字节是 "value" 引用,并改变移位方向。
#include <iostream>
#include <fstream>
using namespace std;
using magic_bytes_t = uint64_t;
const magic_bytes_t search_key{ 0x1234567890abcdef };
const magic_bytes_t replacemenet_key{ 0x1212121212121212 };
struct data_struct
{
const magic_bytes_t value_to_replace;
};
union parsing_union
{
magic_bytes_t value;
uint8_t bytes[sizeof(magic_bytes_t)];
};
int main()
{
std::fstream myFile("C:\Users\crazy_path\x64\Debug\SampleApplication.exe", ios::in | ios::out | ios::binary);
if (!myFile) {
cout << "Couldn't open file" << endl;
return EXIT_FAILURE;
} else {
parsing_union parsing_helper{ 0x0000000000000000 };
uint8_t &single_byte_value = parsing_helper.bytes[7];
while (myFile.read((char*)&single_byte_value, sizeof(single_byte_value)))
{
if (parsing_helper.value == search_key)
{
uint64_t control_key_start_position = myFile.tellg();
control_key_start_position -= sizeof(parsing_helper.value);
myFile.seekp(control_key_start_position);
myFile.write(reinterpret_cast<const char*>(&replacemenet_key), sizeof(replacemenet_key));
cout << "GOT EM !! GOT EM GOOD" << endl;;
break;
} else {
parsing_helper.value >>= (sizeof(single_byte_value) * 8);
}
}
}
system("pause");
return EXIT_SUCCESS;
}
这可能看起来有点贫民窟,但您可以将整个文件加载到字节数组中,然后将字节取消引用到 uint64_t,如下所示:
(是的,抱歉,我没有包含完整的代码,但这应该会给你一个 idea/be 清楚)
byte* bytes = new byte[filesizeinbytes];
//read to the byte array
then:
DWORD offset = 0;
while( *(uint64_t*)((DWORD)bytes+offset) != 0x1234567890abcdef )
{
offset++;
}
//We found the right address, so we can replace the bytes/address/offset
*(uint64_t*)((DWORD)bytes+offset) = 0x111111111111111;
//write the entire file, starting from bytes till the end of the file
delete[] bytes; // free the allocated memory
bytes = 0;