我永远无法将数据恢复为十六进制形式的原始 unsigned char,以便我可以将数据加载到内存中......
ByteQueue 和 MessageQueue 是更高级别的 Crypto++ 管道对象。当data is flowing from a source to a sink 他们是一个不错的选择。但是当你不使用水槽时,它们可能会有点尴尬,比如你的memcpy。
下面是两个做你想做的事的例子。
还要注意这并不完全正确。由于 CBC 模式和 PKCS 填充,密文大小必须是块大小的倍数。在您的情况下,加密的 shellcode 应该是 16 个字节。
const byte enc_shellcode[] ="\x6D\x30\xEB\x18\xF2\x01\x16";
管道
@zett42 有正确的想法 - 使用 ArraySink,Crypto++ 管道将为您执行 memcpy。事实上,您甚至不需要plain 或recover。所以它看起来像下面这样。 (我在Linux上工作,所以我需要伪造VirtualAlloc)。
$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "modes.h"
#include "files.h"
#include "aes.h"
#include "hex.h"
#include <iostream>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
HexEncoder encoder(new FileSink(std::cout));
ByteQueue cipher;
const byte shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60";
const byte key[16] = {1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4};
const byte iv[16] = {8,7,6,5, 8,7,6,5, 8,7,6,5, 8,7,6,5};
//Encryption
CBC_Mode<AES>::Encryption enc;
enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
ArraySource plain(shellcode, 7, true);
StreamTransformationFilter f1(enc, new Redirector(cipher));
plain.CopyTo(f1);
f1.MessageEnd();
std::cout << "Cipher text: ";
cipher.CopyTo(encoder);
encoder.MessageEnd();
std::cout << std::endl;
// Allocating memory with EXECUTE writes
// void* exec = VirtualAlloc(0, sizeof test, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Proxy for VirtualAlloc
byte x[7];
void* exec = reinterpret_cast<void*>(x);
// Decryption
CBC_Mode<AES>::Decryption dec;
dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
ArraySink recover(reinterpret_cast<byte*>(exec), 7);
StreamTransformationFilter f2(dec, new Redirector(recover));
cipher.CopyTo(f2);
f2.MessageEnd();
// Can't use recover.CopyTo() here. ArraySink is not a source;
// and the internal pointer is at the end of the array, not
// the beginning of the array.
std::cout << "Recover text: ";
encoder.Put(reinterpret_cast<byte*>(exec), 7);
encoder.MessageEnd();
std::cout << std::endl;
return 0;
}
运行代码会产生以下输出。
$ g++ test.cxx ./libcryptopp.a -o test.exe
$ ./test.exe
Cipher text: 88BFA35C6ABF2EDF1FDCDC354721C72C
Recover text: FCE88900000060
C++ 对象
您也可以使用 C++ 对象而不是 Crypto++ ByteQueue。这更容易使用。
$ cat test.cxx
#include "cryptlib.h"
#include "filters.h"
#include "osrng.h"
#include "modes.h"
#include "files.h"
#include "aes.h"
#include "hex.h"
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
HexEncoder encoder(new FileSink(std::cout));
// The embedded NULLs mean we need to use this ctor
const std::string shellcode("\xfc\xe8\x89\x00\x00\x00\x60", 7);
std::string cipher;
const byte key[16] = {1,2,3,4, 1,2,3,4, 1,2,3,4, 1,2,3,4};
const byte iv[16] = {8,7,6,5, 8,7,6,5, 8,7,6,5, 8,7,6,5};
//Encryption
CBC_Mode<AES>::Encryption enc;
enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
StreamTransformationFilter f1(enc, new StringSink(cipher));
StringSource(shellcode, true, new Redirector(f1));
std::cout << "Cipher text: ";
StringSource(cipher, true, new Redirector(encoder));
std::cout << std::endl;
// Allocating memory with EXECUTE writes
// void* exec = VirtualAlloc(0, sizeof test, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Proxy for VirtualAlloc
byte x[7];
void* exec = reinterpret_cast<void*>(x);
// Decryption
CBC_Mode<AES>::Decryption dec;
dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
ArraySink recover(reinterpret_cast<byte*>(exec), 7);
StreamTransformationFilter f2(dec, new Redirector(recover));
StringSource(cipher, true, new Redirector(f2));
// Can't use recover.CopyTo() here. ArraySink is not a source;
// and the internal pointer is at the end of the array, not
// the beginning of the array.
std::cout << "Recover text: ";
encoder.Put(reinterpret_cast<byte*>(exec), 7);
encoder.MessageEnd();
std::cout << std::endl;
return 0;
}
使用std::string得到同样的结果:
$ g++ test.cxx ./libcryptopp.a -o test.exe
$ ./test.exe
Cipher text: 88BFA35C6ABF2EDF1FDCDC354721C72C
Recover text: FCE8899B7F0000