在阅读了几本关于密码学和运行时PE加密器的白皮书后,我决定自己编写.它非常简单,仅用于教育目的.
这是GitHub回购:https://github.com/Jyang772/XOR_Crypter
我有两个问题.
首先,为什么我必须不断更改我的文件权限以启动每个输出的.exe(由Builder.exe创建的文件而不是编译器)?它创建一个文件Shared
.我必须右键单击它并选择共享Nobody
.这与文件访问和安全权限有关吗?我正在使用CreateFile()
和Readfile
读写输入和输出文件.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
其次,我似乎无法让XOR加密工作.对于我所做的事情来说,这似乎很简单.字节大小相同.在我调查时,我让Builder和Stub各自输出一个文件数据未加密的文件.他们是一样的.然后我尝试加密数据.毫无疑问,数据是使用密码加密的,但是稍后当存根解密时它会显示为空白.我糊涂了.
这是我的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读取该内容并确定使用哪种加密方法来解密数据.
首先,使用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 }
并且你的"存根"中的解密应该是xor_crypt( key, RData );
.
我有一个最后的想法.我在"Stub"程序中看到的最大的错误是这一行:
switch (RData[strlen(RData)-1])
一旦你对数据进行XOR加密,一些字节将变为零.该strlen()
函数不会返回RData
结果中最后一个字节的索引.并且,有一个不同的,更微妙的错误:它返回字符串的最后一个字节,而不是资源的最后一个字节.我真的不明白这条线是如何正确的; 更确切地说,我怀疑你的程序在加密被禁用的时候仍在工作,通过default
切换到switch-case.
如果您真的打算根据资源有效负载的最后一个字节来区分不同类型的数据,那么您真的应该使用Windows API返回的大小来查找该字节.
如果你vector<char>
按照我的建议切换到使用,那么你可以找到它RData.back()
.否则,如果继续使用char *
,那么该字节就是RData[RSize - 1]
.