在阅读了几篇关于密码学和运行时PE加密器的白皮书后,我决定自己编写。它非常简单,仅用于教育目的。
以下是GitHub回购:https://github.com/Jyang772/XOR_Crypter
我有两个问题。
Shared
的文件。我必须右键单击它并选择与Nobody
共享。这与文件访问和安全权限有关吗?我正在使用CreateFile()
和Readfile
来读取和写入输入和输出文件。 http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
这是我的XOR实现:
fs =字节大小 Rsize =字节大小 应该是一样的。
生成器:
char cipher[] ="penguin";
for (int i = 0; i < fs; i++)
{
FB[i] ^= cipher[i % strlen(cipher)]; // Simple Xor chiper
}
存根:
char cipher[] = "penguin";
for (int i = 0; i < Rsize; i++)
{
RData[i] ^= cipher[i % strlen(cipher)];
}
如果我要在Builder和Stub中注释掉加密功能,那么加密文件运行正常。呃,除了权限错误。
我还尝试包含一个选项菜单,用户可以在其中选择使用的加密方法。也许我可能在那里做错了什么? Builder.exe将包含用户选择的一个字节添加到FB
缓冲区的末尾。 Stub.exe读取该内容并确定使用哪种加密方法来解密数据。
答案 0 :(得分:12)
首先,使用XOR“加密”,您的“加密”和“解密”功能应该相同:
void xor_crypt(const char *key, int key_len, char *data, int data_len)
{
for (int i = 0; i < data_len; i++)
data[i] ^= key[ i % key_len ];
}
您应该能够在“XOR Crypter”程序和“Stub”程序中使用相同的功能。
这不是一个非常C ++的风格;通常你会使用std::string
或std::vector
。例如:
void xor_crypt(const std::string &key, std::vector<char>& data)
{
for (size_t i = 0; i != data.size(); i++)
data[i] ^= key[ i % key.size() ];
}
然后在调用它的程序中,你声明:
std::string key = "penguin";
你会像这样阅读你的文件:
std::vector<char> file_data; // With your current program, make this a global.
fs = GetFileSize(efile, NULL);
file_data.resize(fs); // set vector length equal to file size
// Note: Replace &( file_data[0] ) with file_data.data() if you have C++11 support
ReadFile(efile, (LPVOID)( &( file_data[0] )), fs, &bt, NULL);
if (fs != bt)
// error reading file: report it here.
然后您只需使用xor_crypt( key, file_data );
加密即可。要将XOR加密数据写入您的资源,我相信您可以使用以下命令调用现有函数:
// replace &( file_data[0] ) with file_data.data() if C++11
WriteToResources(output, 1, (BYTE *)&( file_data[0] ), file_data.size() );
我怀疑真正的问题在于您正在使用的Windows API。 LoadResource
是否为您提供了可变数据,或者您是否需要复制它?我不知道Windows API,但如果LoadResource
为您提供只读副本,我不会感到惊讶。
如果您确实需要制作自己的副本以修改资源,那么在“Stub”程序中恢复XOR加密的资源应该如下所示:
std::vector<char> RData;
void Resource(int id)
{
size_t Rsize;
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(1), RT_RCDATA);
HGLOBAL temp = LoadResource(NULL, hResource);
Rsize = SizeofResource(NULL, hResource);
RData.resize(RSize);
memcpy( (void*)&(RData[0]), temp, RSize ); // replace &RData[0] with RData.data() if C++11
}
并且“Stub”中的解密应为xor_crypt( key, RData );
。
我有一个最后的想法。我在“Stub”程序中看到的最大的错误是这一行:
switch (RData[strlen(RData)-1])
一旦你对数据进行XOR加密,一些字节将变为零。 strlen()
函数不会返回RData
中最后一个字节的索引。并且,有一个不同的,更微妙的错误:它返回字符串的最后一个字节,而不是资源的最后一个字节。我真的不明白这条线是如何正确的;相反,我怀疑你的程序在加密被禁用的情况下仍在工作,通过切换到switch-case的default
。
如果您真的打算根据资源有效负载的最后一个字节来区分不同类型的数据,那么您真的应该使用Windows API返回的大小来查找该字节。
如果您按照我的建议切换到使用vector<char>
,那么您可以使用RData.back()
找到它。否则,如果您继续使用char *
,则该字节将为RData[RSize - 1]
。
答案 1 :(得分:2)
根据您的内容数据,在调用strcat(FB,choice)时,在FB指定的已分配内存中或在“C ++ Builder / main.cpp”之后(buffer overrun)写入char选项。
修复:在FB中为数据+选项char分配足够的空间。在处理二进制数据时,不应使用字符串函数(例如:strcat)。
FB = new char[fs + 1];
memcpy(FB +fs, option, 1); // copy the option at end