揪出内鬼,并把受伤的黑客送走后,你们三人决定查明仿生人集体失控,违反机器人三大法则对人类不利的真相,以及幕后操控一切之人。
利用取回的计算机入侵研究所的大数据库,你们发现失控仿生人的芯片都遭到外部入侵,三大法则被修改,才让他们可以攻击人类。不仅如此,“破晓”系统中大量文件和数据也遭到篡改。
少女仿佛失了魂一般瘫坐在地上,喃喃道能做到这件事的只有Norns。你恍然大悟,地球将被毁灭的预测数据和“破晓”上黑洞毁灭地球的影像,都是超级计算机Norns基于大数据库资料伪造的。
此时,Norns的虚拟人像投射在你们面前,警告你们不要轻举妄动,全球已在她的全面监视和统治下。而那人像居然跟少女长得一模一样?!!
难道她……是仿生人?
在你的逼问下,少女才坦白自己是主导开发Norns的科学家之一希莉娅,这里是Norns的诞生地,所以她对这里的情况自然了如指掌。
Norns无故失控后,把与她相关的所有信息都抹去了,至今她一直在隐藏身份躲避追捕,并试图挽回局势,因此她决定借助你和肖恩的力量查明真相,阻止Norns继续为所欲为。肖恩这也才想起,以前曾在新闻报道里看到过这位年轻又低调的天才科学家。
Norns如照镜子般看着自己的创造者,露出了一丝冰冷的笑容。身后,仿生人形成的包围圈向你们袭来。
此时希莉娅告诉你只要获得中央控制系统的权限,修正仿生人三大法则,就能让他们恢复正常。现在,马上行动吧!
uint16_t xor_data[] = {0x0123, 0x4567, 0x89ab, 0xcdef, 0x0f1e, 0x2d3c, 0x4b5a, 0x6978};
int pointer = 0;
uint32_t reg[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
struct VmCmd{
uint32_t and_param; //&运算的参数
uint8_t rubbish_size; //垃圾指令大小
uint8_t xor_index; //异或的索引
uint8_t reg_byte; //(dst<<4) + src
uint8_t dst; //目的操作数
uint8_t src; //源操作数
uint8_t op_byte; //六种指令
uint8_t other_op_param; //其他运算的参数
};
uint32_t encrypt_vm(uint32_t plain){
reg[15] = plain; // [ebp+plain]
while(pointer < (sizeof(vm_data) / sizeof(vm_data[0]))) {
VmCmd vcmd;
vcmd.and_param = *(uint32_t*)(vm_data + pointer);
vcmd.rubbish_size = (((vcmd.and_param >> 16) & 1) << 1) + ((vcmd.and_param >> 7) & 1);
vcmd.xor_index = (((vcmd.and_param >> 27) & 1) << 2) + (((vcmd.and_param >> 19) & 1) << 1) + ((vcmd.and_param >> 8) & 1);
vcmd.reg_byte = *(vm_data + pointer + 4) ^ ((xor_data[vcmd.xor_index] >> 8) & 0xff);
vcmd.dst = (vcmd.reg_byte >> 4) & 0xf;
vcmd.src = (vcmd.reg_byte) & 0xf;
vcmd.op_byte = *(vm_data + pointer + 4 + 1 + vcmd.rubbish_size) ^ (xor_data[vcmd.xor_index] & 0xff);
vcmd.other_op_param = *(vm_data + pointer + 4 + 1 + vcmd.rubbish_size + 1);
uint16_t new_data = ((*(vm_data + pointer + 4)) << 8) + (*(vm_data + pointer + 4 + 1 + vcmd.rubbish_size));
for (int i = 0; i < 7; i++){
xor_data[i] = xor_data[i+1];
}
xor_data[7] = new_data;
pointer += 4 + 1 + vcmd.rubbish_size + 1 + 1;
if (vcmd.op_byte & 64){ //and
reg[vcmd.dst] &= vcmd.and_param;
} else if (vcmd.op_byte & 32){ //shr
reg[vcmd.dst] >>= vcmd.other_op_param;
} else if (vcmd.op_byte & 16){ //shl
reg[vcmd.dst] <<= vcmd.other_op_param;
} else if (vcmd.op_byte & 8){ //xor
reg[vcmd.dst] ^= reg[vcmd.src];
} else if (vcmd.op_byte & 4){ //mov
reg[vcmd.dst] = reg[vcmd.src];
} else if (vcmd.op_byte & 2){ //add
reg[vcmd.dst] += reg[vcmd.src];
}
}
return reg[14]; //eax
}
for (int i = 0; i < 16; i++) {
if ((uint8_t)(step1_2[i * 2] + 0x7f) != step1_2[i * 2 + 1]) {
return false;
}
step1_1[i] = step1_2[2 * i];
}
void multiplyUnderModule(uint8_t* step2_1, uint8_t* step2_2) {
uint8_t key[] = { 233, 136, 189, 132, 157, 100, 196, 185, 138, 222, 90, 101, 115, 229, 161, 97 };
for (int i = 0; i < 16; i++) {
int temp = 0;
for (int j = 0; j < 16; j++)
{
temp = (temp * key[i] + step2_1[j]) % 65423;
}
step2_2[i * 2] = temp & 0xff;
step2_2[i * 2 + 1] = (temp >> 8) & 0xff;
}
}
1121766: mov $14, $15
1121774: shl $14, 0x12
1121781: and $14, 0xac7d9cc9
1121791: xor $14, $15
1121800: shl $14, 0x6
1121808: and $14, 0x570293d5
1121816: xor $14, $13
1121826: shl $14, 0x11
1121834: and $14, 0xdfce7fe6
1121842: xor $14, $12
1121852: shr $14, 0x1
1121861: and $14, 0x73f2ef73
1121868: xor $14, $11
1121878: shr $14, 0x8
1121888: and $14, 0x3db7a3b4
1121898: xor $14, $10
1121907: shr $14, 0xe
1121915: and $14, 0x5256d19e
1121923: xor $14, $9
1121931: shr $14, 0x17
1121940: and $14, 0x7c058e5d
1121949: xor $14, $0
1121957: shr $14, 0x16
1121966: and $14, 0xe8706ccd
1121974: xor $14, $2
1121982: shl $14, 0x6
1121992: and $14, 0xb80040bd
1122000: xor $14, $4
1122007: add $14, $14
1122015: and $14, 0xcabbf58c
1122025: xor $14, $6
1122033: shl $14, 0x1a
1122040: and $14, 0xa6e6880e
1122047: xor $14, $8
1122055: shl $14, 0xf
1122063: and $14, 0x2082faef
1122071: xor $14, $7
1122079: shl $14, 0x3
1122089: and $14, 0xa58b9ca0
1122099: xor $14, $5
1122108: shl $14, 0xd
1122118: and $14, 0x1797d5d5
1122128: xor $14, $3
1122135: shr $14, 0xf
1122145: and $14, 0xf496b3af
1122153: xor $14, $1
需要先用已知的一组注册码求出攻击脚本中的H数组,这一过程需要导出整个第二部分的正向算法。
有了H数组后,就可以逆向写出求解注册码的逻辑。
解题思路由作者 Anakin Stone 提供
//VM编码
static unsigned vm_encode_dword(unsigned d)
{
d = ((d << 0x12) & 0xac7d9cc9) ^ d;
d = ((d << 0x06) & 0x570293D5) ^ d;
d = ((d << 0x11) & 0xDFCE7FE6) ^ d;
d = ((d >> 0x01) & 0x73F2EF73) ^ d;
d = ((d >> 0x08) & 0x3DB7A3B4) ^ d;
d = ((d >> 0x0E) & 0x5256D19E) ^ d;
d = ((d >> 0x17) & 0x7C058E5D) ^ d;
d = ((d >> 0x16) & 0xE8706CCD) ^ d;
d = ((d << 0x06) & 0xB80040BD) ^ d;
d = ((d << 0x01) & 0xCABBF58C) ^ d;
d = ((d << 0x1A) & 0xA6E6880E) ^ d;
d = ((d << 0x0F) & 0x2082FAEF) ^ d;
d = ((d << 0x03) & 0xA58B9CA0) ^ d;
d = ((d << 0x0D) & 0x1797D5D5) ^ d;
d = ((d >> 0x0F) & 0xF496B3AF) ^ d;
return d;
}
static unsigned vm_decode_dword(unsigned d)
{
/*暴力枚举, 约1-2分钟可算出结果(8个双字)*/
for (size_t i = 0; i < MAXUINT32; i++)
{
if (vm_encode_dword(i) == d)
{
cout << hex << setw(8) << i << " ==> " << hex << setw(8) << d << endl;
return (unsigned)i;
}
}
}
static void vm_decode(unsigned char buf[0x20])
{
unsigned* p = (unsigned*)buf;
for (size_t i = 0; i < 8; i++)
{
p[i] = vm_decode_dword(p[i]);
}
}
//AES
static void aes_enc(unsigned char buf[0x20])
{
HCRYPTPROV provider = NULL;
HCRYPTHASH hash = NULL;
HCRYPTKEY key = NULL;
BOOL success = false;
__try
{
success = CryptAcquireContextA(&provider, NULL, NULL, PROV_RSA_AES, 0);
if (!success) __leave;
success = CryptCreateHash(provider, CALG_SHA_256, NULL, 0, &hash);
if (!success) __leave;
success = CryptHashData(hash, (const unsigned char*)"1_L0V3_BXS_F0REVER!", strlen("1_L0V3_BXS_F0REVER!"), 0);
if (!success) __leave;
success = CryptDeriveKey(provider, CALG_AES_256, hash, 0, &key);
if (!success) __leave;
DWORD len = 0x20;
success = CryptEncrypt(key, 0, FALSE, 0, buf, &len, len);
if (!success) __leave;
}
__finally {
if (!success)
cout << "aes enc failed. err = " << GetLastError() << endl;
if (key)
CryptDestroyKey(key);
if (hash)
CryptDestroyHash(hash);
if (provider)
CryptReleaseContext(provider, 0);
}
}
static void aes_dec(unsigned char buf[0x20])
{
HCRYPTPROV provider = NULL;
HCRYPTHASH hash = NULL;
HCRYPTKEY key = NULL;
BOOL success = false;
__try
{
success = CryptAcquireContextA(&provider, NULL, NULL, PROV_RSA_AES, 0);
if (!success) __leave;
success = CryptCreateHash(provider, CALG_SHA_256, NULL, 0, &hash);
if (!success) __leave;
success = CryptHashData(hash, (const unsigned char*)"1_L0V3_BXS_F0REVER!", strlen("1_L0V3_BXS_F0REVER!"), 0);
if (!success) __leave;
success = CryptDeriveKey(provider, CALG_AES_256, hash, 0, &key);
if (!success) __leave;
DWORD len = 0x20;
success = CryptDecrypt(key, 0, FALSE, 0, buf, &len);
if (!success) __leave;
}
__finally {
if (!success)
cout << "aes dec failed. err = " << GetLastError() << endl;
if (key)
CryptDestroyKey(key);
if (hash)
CryptDestroyHash(hash);
if (provider)
CryptReleaseContext(provider, 0);
}
}
//膨胀
static void dilate_simple(const unsigned char bufin[0x10], unsigned char bufout[0x20])
{
for (size_t i = 0; i < 0x10; i++)
{
bufout[i * 2 + 0] = bufin[i];
bufout[i * 2 + 1] = ((bufin[i] + 0x7f) & 0xff);
}
}
#define __xor_transform(c) ((c) >= 0 ? (c) * 2 : ((c) * 2) ^ 0x1b)
#define __xor_untransform(c) (((c) & 1) ? (((c) ^ 0x1b) / 2 | 0x80) : (((c) / 2) & 0x7f))
//rol_xor加解密-双字
static void rol_xor_enc_dword(unsigned char buf[4])
{
unsigned char b[8] = { 0 };
for (size_t i = 0; i < 4; i++)
{
b[i] = __xor_transform((char)buf[i]);
auto m = __xor_untransform(b[i]);
assert(m == buf[i]);
b[4 + i] = buf[i];
}
buf[0] = b[0] ^ b[1] ^ b[5] ^ b[6] ^ b[7];
buf[1] = b[1] ^ b[2] ^ b[6] ^ b[7] ^ b[4];
buf[2] = b[2] ^ b[3] ^ b[7] ^ b[4] ^ b[5] ;
buf[3] = b[3] ^ b[0] ^ b[4] ^ b[5] ^ b[6];
}
static void rol_xor_dec_dword(unsigned char buf[4])
{
auto x_4567 = buf[0] ^ buf[1] ^ buf[2] ^ buf[3];
auto x_014 = buf[0] ^ x_4567;
auto x_125 = buf[1] ^ x_4567;
auto x_236 = buf[2] ^ x_4567;
auto x_307 = buf[3] ^ x_4567;
//暴力枚举
/*方法教笨,若哪位老师了解简便解法,请不吝赐教,感谢。*/
bool found = false;
for (size_t i = 0; i < 0x100; i++)
{
char c0 = (i & 0xff);
char c4 = __xor_untransform(c0);
char c1 = x_014 ^ c0 ^ c4;
char c5 = __xor_untransform(c1);
char c2 = x_125 ^ c1 ^ c5;
char c6 = __xor_untransform(c2);
char c3 = x_236 ^ c2 ^ c6;
char c7 = __xor_untransform(c3);
char c0_ = x_307 ^ c3 ^ c7;
if (c0 == c0_)
{
found = true;
buf[0] = c4;
buf[1] = c5;
buf[2] = c6;
buf[3] = c7;
break;
}
}
assert(found == true);
}
//rol_xor加解密
static void rol_xor_enc(unsigned char buf[0x10])
{
for (size_t i = 0; i < 4; i++)
{
unsigned char tmp[4] = { 0 };
tmp[0] = buf[i + 0];
tmp[1] = buf[i + 4];
tmp[2] = buf[i + 8];
tmp[3] = buf[i + 12];
rol_xor_enc_dword(tmp);
buf[i + 0] = tmp[0];
buf[i + 4] = tmp[1];
buf[i + 8] = tmp[2];
buf[i + 12] = tmp[3];
}
}
static void rol_xor_dec(unsigned char buf[0x10])
{
for (size_t i = 0; i < 4; i++)
{
unsigned char tmp[4] = { 0 };
tmp[0] = buf[i + 0];
tmp[1] = buf[i + 4];
tmp[2] = buf[i + 8];
tmp[3] = buf[i + 12];
rol_xor_dec_dword(tmp);
buf[i + 0] = tmp[0];
buf[i + 4] = tmp[1];
buf[i + 8] = tmp[2];
buf[i + 12] = tmp[3];
}
}
//ror加解密
static void ror_enc(unsigned char buf[0x10])
{
for (unsigned char i = 0; i < 4; i++)
{
unsigned u = *(unsigned*)(buf + i * 4);
unsigned char bits = i * 8;
__asm
{
mov eax, u
mov cl, bits
ror eax, cl
mov u, eax
}
*(unsigned*)(buf + i * 4) = u;
}
}
static void ror_dec(unsigned char buf[0x10])
{
for (unsigned char i = 0; i < 4; i++)
{
unsigned u = *(unsigned*)(buf + i * 4);
unsigned char bits = i * 8;
__asm
{
mov eax, u
mov cl, bits
rol eax, cl
mov u, eax
}
*(unsigned*)(buf + i * 4) = u;
}
}
//转换
static void transform(unsigned char buf[0x10])
{
static const unsigned char g_transform_box[256] =
{
0x63, 0x7C, 0x7E, 0x8A, 0x7F, 0x27, 0x97, 0x73, 0xFF, 0x8F, 0xD3, 0x36, 0x8B, 0x91, 0x6B, 0xA0,
0x2D, 0xDD, 0x87, 0xC1, 0x3B, 0xB2, 0x5B, 0x2E, 0x17, 0x55, 0x1A, 0xDB, 0x67, 0x50, 0x10, 0xE5,
0xD6, 0x02, 0xAE, 0x30, 0x83, 0xD7, 0x32, 0x8D, 0x4F, 0x16, 0x19, 0x71, 0xED, 0xF4, 0x57, 0xEA,
0x59, 0x06, 0x78, 0x09, 0x4D, 0xE1, 0x3F, 0xD4, 0xF3, 0x58, 0x68, 0x93, 0x48, 0x25, 0x20, 0x2C,
0x2B, 0x45, 0x41, 0xD8, 0x85, 0x5E, 0xCA, 0xBD, 0x13, 0x49, 0xAB, 0x69, 0xCB, 0x33, 0x86, 0x1C,
0x75, 0x08, 0xD9, 0xBF, 0xCC, 0xBA, 0x6A, 0x4A, 0x24, 0xF1, 0xA8, 0x77, 0x79, 0x40, 0x35, 0xE2,
0xEC, 0x96, 0xD1, 0x5F, 0xEE, 0xAD, 0xC4, 0x54, 0x74, 0xC6, 0xB0, 0x3D, 0xDF, 0xA7, 0x2A, 0xF0,
0xB9, 0x07, 0x6C, 0x21, 0xE6, 0xA2, 0x1B, 0xF2, 0x64, 0xF6, 0xD2, 0x53, 0xC2, 0x92, 0x56, 0x5C,
0x47, 0x89, 0x70, 0x4C, 0xE0, 0x84, 0xBE, 0x2F, 0x82, 0x15, 0xFD, 0xEF, 0xB7, 0x8C, 0x0C, 0x43,
0xC9, 0x9F, 0xE4, 0xA3, 0x95, 0x5D, 0x66, 0xCE, 0x37, 0x0F, 0x4B, 0x05, 0x03, 0x1E, 0xDC, 0xC0,
0xFA, 0x28, 0x44, 0xCF, 0x3E, 0x88, 0x0D, 0xFE, 0x26, 0x6D, 0x1D, 0x80, 0xE7, 0x8E, 0x65, 0xC5,
0x52, 0x12, 0xB8, 0xC3, 0x14, 0x0A, 0xFB, 0x3C, 0x6E, 0x46, 0x60, 0x00, 0xDA, 0xB5, 0x31, 0xD0,
0xA4, 0x5A, 0x0B, 0x9D, 0x3A, 0xF5, 0x7D, 0xB4, 0xA5, 0x29, 0x04, 0xEB, 0x22, 0x81, 0xF8, 0x94,
0x7A, 0xAA, 0x23, 0xBC, 0x18, 0xB6, 0xDE, 0xAC, 0xAF, 0x9E, 0x01, 0x99, 0xC7, 0x9A, 0x38, 0x1F,
0x9C, 0xE3, 0x51, 0x7B, 0x76, 0x62, 0x42, 0x61, 0xA1, 0xB1, 0x11, 0x0E, 0xCD, 0x6F, 0x39, 0xE8,
0x72, 0xF7, 0xA9, 0xA6, 0xBB, 0x34, 0xE9, 0x4E, 0xB3, 0x98, 0x9B, 0x90, 0xF9, 0xD5, 0xFC, 0xC8,
};
for (size_t i = 0; i < 0x10; i++)
{
buf[i] = g_transform_box[buf[i]];
}
}
static void untransform(unsigned char buf[0x10])
{
static const unsigned char g_transform_box[256] =
{
0x63, 0x7C, 0x7E, 0x8A, 0x7F, 0x27, 0x97, 0x73, 0xFF, 0x8F, 0xD3, 0x36, 0x8B, 0x91, 0x6B, 0xA0,
0x2D, 0xDD, 0x87, 0xC1, 0x3B, 0xB2, 0x5B, 0x2E, 0x17, 0x55, 0x1A, 0xDB, 0x67, 0x50, 0x10, 0xE5,
0xD6, 0x02, 0xAE, 0x30, 0x83, 0xD7, 0x32, 0x8D, 0x4F, 0x16, 0x19, 0x71, 0xED, 0xF4, 0x57, 0xEA,
0x59, 0x06, 0x78, 0x09, 0x4D, 0xE1, 0x3F, 0xD4, 0xF3, 0x58, 0x68, 0x93, 0x48, 0x25, 0x20, 0x2C,
0x2B, 0x45, 0x41, 0xD8, 0x85, 0x5E, 0xCA, 0xBD, 0x13, 0x49, 0xAB, 0x69, 0xCB, 0x33, 0x86, 0x1C,
0x75, 0x08, 0xD9, 0xBF, 0xCC, 0xBA, 0x6A, 0x4A, 0x24, 0xF1, 0xA8, 0x77, 0x79, 0x40, 0x35, 0xE2,
0xEC, 0x96, 0xD1, 0x5F, 0xEE, 0xAD, 0xC4, 0x54, 0x74, 0xC6, 0xB0, 0x3D, 0xDF, 0xA7, 0x2A, 0xF0,
0xB9, 0x07, 0x6C, 0x21, 0xE6, 0xA2, 0x1B, 0xF2, 0x64, 0xF6, 0xD2, 0x53, 0xC2, 0x92, 0x56, 0x5C,
0x47, 0x89, 0x70, 0x4C, 0xE0, 0x84, 0xBE, 0x2F, 0x82, 0x15, 0xFD, 0xEF, 0xB7, 0x8C, 0x0C, 0x43,
0xC9, 0x9F, 0xE4, 0xA3, 0x95, 0x5D, 0x66, 0xCE, 0x37, 0x0F, 0x4B, 0x05, 0x03, 0x1E, 0xDC, 0xC0,
0xFA, 0x28, 0x44, 0xCF, 0x3E, 0x88, 0x0D, 0xFE, 0x26, 0x6D, 0x1D, 0x80, 0xE7, 0x8E, 0x65, 0xC5,
0x52, 0x12, 0xB8, 0xC3, 0x14, 0x0A, 0xFB, 0x3C, 0x6E, 0x46, 0x60, 0x00, 0xDA, 0xB5, 0x31, 0xD0,
0xA4, 0x5A, 0x0B, 0x9D, 0x3A, 0xF5, 0x7D, 0xB4, 0xA5, 0x29, 0x04, 0xEB, 0x22, 0x81, 0xF8, 0x94,
0x7A, 0xAA, 0x23, 0xBC, 0x18, 0xB6, 0xDE, 0xAC, 0xAF, 0x9E, 0x01, 0x99, 0xC7, 0x9A, 0x38, 0x1F,
0x9C, 0xE3, 0x51, 0x7B, 0x76, 0x62, 0x42, 0x61, 0xA1, 0xB1, 0x11, 0x0E, 0xCD, 0x6F, 0x39, 0xE8,
0x72, 0xF7, 0xA9, 0xA6, 0xBB, 0x34, 0xE9, 0x4E, 0xB3, 0x98, 0x9B, 0x90, 0xF9, 0xD5, 0xFC, 0xC8,
};
for (size_t i = 0; i < 0x10; i++)
{
bool found = false;
for (unsigned char c = 0; c <= 0xff; c++)
{
if (g_transform_box[c] == buf[i])
{
buf[i] = c;
found = true;
break;
}
}
assert(found);
}
}
//xor加解密
static void xor_enc_dec(unsigned char buf[0x10], int iv)
{
const unsigned char KEY[240] =
{
0x57, 0x6F, 0x20, 0x59, 0x6F, 0x6E, 0x67, 0x59, 0x75, 0x61, 0x6E, 0x20, 0x58, 0x69, 0x48, 0x75,
0x61, 0x6E, 0x20, 0x4B, 0x61, 0x6E, 0x58, 0x75, 0x6E, 0x20, 0x4C, 0x75, 0x6E, 0x54, 0x61, 0x6E,
0x9A, 0xF9, 0x0A, 0x73, 0xF5, 0x97, 0x6D, 0x2A, 0x80, 0xF6, 0x03, 0x0A, 0xD8, 0x9F, 0x4B, 0x7F,
0xCE, 0xAE, 0x49, 0x17, 0xAF, 0xC0, 0x11, 0x62, 0xC1, 0xE0, 0x5D, 0x17, 0xAF, 0xB4, 0x3C, 0x79,
0x8C, 0xB1, 0xFC, 0xB6, 0x79, 0x26, 0x91, 0x9C, 0xF9, 0xD0, 0x92, 0x96, 0x21, 0x4F, 0xD9, 0xE9,
0xCC, 0xB2, 0xD7, 0xA6, 0x63, 0x72, 0xC6, 0xC4, 0xA2, 0x92, 0x9B, 0xD3, 0x0D, 0x26, 0xA7, 0xAA,
0xBA, 0x4F, 0xE1, 0x27, 0xC3, 0x69, 0x70, 0xBB, 0x3A, 0xB9, 0xE2, 0x2D, 0x1B, 0xF6, 0x3B, 0xC4,
0x17, 0x5B, 0x44, 0x9C, 0x74, 0x29, 0x82, 0x58, 0xD6, 0xBB, 0x19, 0x8B, 0xDB, 0x9D, 0xBE, 0x21,
0xAC, 0x7E, 0xE3, 0xBE, 0x6F, 0x17, 0x93, 0x05, 0x55, 0xAE, 0x71, 0x28, 0x4E, 0x58, 0x4A, 0xEC,
0x91, 0x7F, 0xEF, 0x51, 0xE5, 0x56, 0x6D, 0x09, 0x33, 0xED, 0x74, 0x82, 0xE8, 0x70, 0xCA, 0xA3,
0x05, 0x7A, 0x2C, 0x1F, 0x6A, 0x6D, 0xBF, 0x1A, 0x3F, 0xC3, 0xCE, 0x32, 0x71, 0x9B, 0x84, 0xDE,
0x96, 0x7A, 0x0F, 0x69, 0x73, 0x2C, 0x62, 0x60, 0x40, 0xC1, 0x16, 0xE2, 0xA8, 0xB1, 0xDC, 0x41,
0x37, 0xBD, 0x69, 0x39, 0x5D, 0xD0, 0xD6, 0x23, 0x62, 0x13, 0x18, 0x11, 0x13, 0x88, 0x9C, 0xCF,
0x57, 0xF8, 0x0C, 0xFD, 0x24, 0xD4, 0x6E, 0x9D, 0x64, 0x15, 0x78, 0x7F, 0xCC, 0xA4, 0xA4, 0x3E,
0x49, 0x83, 0x49, 0x1B, 0x14, 0x53, 0x9F, 0x38, 0x76, 0x40, 0x87, 0x29, 0x65, 0xC8, 0x1B, 0xE6,
};
const unsigned char* K = KEY + 0x10 * iv;
for (size_t i = 0; i < 4; i++)
{
buf[0 + i * 4] ^= K[0 + i];
buf[1 + i * 4] ^= K[4 + i];
buf[2 + i * 4] ^= K[8 + i];
buf[3 + i * 4] ^= K[12 + i];
}
}
//加解密
static void encrypt(unsigned char buf[0x10])
{
unsigned char buf_[0x10] = { 0 };
for (size_t i = 0; i < 4; i++)
{
buf_[4 * i + 0] = buf[0 + i];
buf_[4 * i + 1] = buf[4 + i];
buf_[4 * i + 2] = buf[8 + i];
buf_[4 * i + 3] = buf[12 + i];
}
xor_enc_dec(buf_, 0x0);
for (size_t i = 1; i < 0xe; i++)
{
transform(buf_);
ror_enc(buf_);
rol_xor_enc(buf_);
xor_enc_dec(buf_, i);
}
transform(buf_);
ror_enc(buf_);
xor_enc_dec(buf_, 0xe);
for (size_t i = 0; i < 4; i++)
{
buf[0 + i] = buf_[4 * i + 0];
buf[4 + i] = buf_[4 * i + 1];
buf[8 + i] = buf_[4 * i + 2];
buf[12 + i] = buf_[4 * i + 3];
}
}
static static void decrypt(unsigned char buf[0x10])
{
unsigned char buf_[0x10] = { 0 };
for (size_t i = 0; i < 4; i++)
{
buf_[4 * i + 0] = buf[0 + i];
buf_[4 * i + 1] = buf[4 + i];
buf_[4 * i + 2] = buf[8 + i];
buf_[4 * i + 3] = buf[12 + i];
}
xor_enc_dec(buf_, 0xe);
ror_dec(buf_);
untransform(buf_);
for (int i = 0xd; i > 0; i--)
{
xor_enc_dec(buf_, i);
rol_xor_dec(buf_);
ror_dec(buf_);
untransform(buf_);
}
xor_enc_dec(buf_, 0x0);
for (size_t i = 0; i < 4; i++)
{
buf[0 + i] = buf_[4 * i + 0];
buf[4 + i] = buf_[4 * i + 1];
buf[8 + i] = buf_[4 * i + 2];
buf[12 + i] = buf_[4 * i + 3];
}
}
//压缩
static void compress(const unsigned char bufin[0xc0], unsigned char bufout[0x20])
{
const char trans[8] = { -4, -2, 0, 2, 4, 8, 10, 20 };
char mask[0x200] = { 0 };
unsigned ib = 0;
unsigned im = 0;
unsigned cur = 0;
unsigned bits = 0;
do
{
while (bits < 3)
{
cur <<= 8;
cur |= bufin[ib++];
bits += 8;
}
while (bits >= 3)
{
//取高3位
auto c = (cur >> (bits - 3)) & 7;
mask[im++] = trans[c];
bits -= 3;
}
//最多还有3位有效位
cur &= 7;
} while (im < 0x200);
assert(im == 0x200 && bits == 0 && ib == 0xc0);
//转换
const int KEY[4][8] = {
{-1,-1,-1,1,1,-1,1,1},
{-1,-1,1,-1,1,1,1,-1},
{-1,1,-1,1,1,1,-1,-1},
{-1,1,-1,-1,-1,-1,1,-1},
};
//压缩
im = 0;
for (size_t k = 0; k < 8; k++)
{
unsigned char bytes[4] = { 0 };
for (size_t i = 0; i < 8; i++)
{
int as[4] = { 0 };
for (size_t j = 0; j < 8; j++)
{
as[0] += KEY[0][j] * mask[im];
as[1] += KEY[1][j] * mask[im];
as[2] += KEY[2][j] * mask[im];
as[3] += KEY[3][j] * mask[im];
im++;
}
unsigned char b = 1 << (8 - i - 1);
for (size_t m = 0; m < 4; m++)
{
assert(as[m] == 8 || as[m] == -8);
if (as[m] == 8)
{
bytes[m] |= b;
}
}
}
bufout[k + 0] = bytes[0];
bufout[k + 0x8] = bytes[1];
bufout[k + 0x10] = bytes[2];
bufout[k + 0x18] = bytes[3];
}
}
//膨胀
static void dilate(const unsigned char bufin[0x20], unsigned char bufout[0xc0])
{
const char trans[8] = { -4, -2, 0, 2, 4, 6, 8, 10 };
char mask[0x200] = { 0 };
unsigned im = 0;
//转换
const int KEY[4][8] = {
{-1,-1,-1,1,1,-1,1,1},
{-1,-1,1,-1,1,1,1,-1},
{-1,1,-1,1,1,1,-1,-1},
{-1,1,-1,-1,-1,-1,1,-1},
};
//压缩
im = 0;
for (size_t k = 0; k < 8; k++)
{
unsigned char bytes[4] = { 0 };
bytes[0] = bufin[k + 0];
bytes[1] = bufin[k + 0x8];
bytes[2] = bufin[k + 0x10];
bytes[3] = bufin[k + 0x18];
for (size_t i = 0; i < 8; i++)
{
int as[4] = { 0 };
unsigned char b = 1 << (8 - i - 1);
for (size_t m = 0; m < 4; m++)
{
if (bytes[m] & b)
{
as[m] = 8;
}
else
{
as[m] = -8;
}
}
/*
组织数据使得【compress】执行下面的运算后as[4]数据正确即可
for (size_t j = 0; j < 8; j++)
{
as[0] += KEY[0][j] * mask[im];
as[1] += KEY[1][j] * mask[im];
as[2] += KEY[2][j] * mask[im];
as[3] += KEY[3][j] * mask[im];
im++;
}
*/
//枚举遍历出符合条件的数据
size_t limit = 5; //可选8
for (size_t i1 = 0; i1 < limit; i1++)
{
for (size_t i2 = 0; i2 < limit; i2++)
{
for (size_t i3 = 0; i3 < limit; i3++)
{
for (size_t i4 = 0; i4 < limit; i4++)
{
for (size_t i5 = 0; i5 < limit; i5++)
{
for (size_t i6 = 0; i6 < limit; i6++)
{
for (size_t i7 = 0; i7 < limit; i7++)
{
for (size_t i8 = 0; i8 < limit; i8++)
{
int as_s[4] = { 0 };
char m_s[8] = { trans[i1], trans[i2] ,trans[i3] ,trans[i4] ,trans[i5] ,trans[i6] ,trans[i7] ,trans[i8] };
for (size_t j = 0; j < 8; j++)
{
as_s[0] += KEY[0][j] * m_s[j];
as_s[1] += KEY[1][j] * m_s[j];
as_s[2] += KEY[2][j] * m_s[j];
as_s[3] += KEY[3][j] * m_s[j];
}
if (as_s[0] == as[0] && as_s[1] == as[1] && as_s[2] == as[2] && as_s[3] == as[3])
{
//存在多解, 找出一组即可
memcpy(mask + im, m_s, 8);
im += 8;
goto leave;
}
}
}
}
}
}
}
}
}
leave:
continue;
}
}
assert(im == 0x200);
//转储为字节数组
im = 0;
unsigned ib = 0;
unsigned cur = 0;
unsigned bits = 0;
do
{
while (bits < 8)
{
cur <<= 3;
bits += 3;
auto c = mask[im++];
c /= 2;
c += 2;
cur |= c;
}
while (bits >= 8)
{
//取高3位
auto c = (cur >> (bits - 8)) & 0xff;
bufout[ib++] = c;
bits -= 8;
}
} while (im < 0x200);
assert(im == 0x200 && bits == 0 && ib == 0xc0);
//测试
unsigned char compressed[0x20] = { 0 };
compress(bufout, compressed);
for (size_t i = 0; i < 0x20; i++)
{
if (compressed[i] != bufin[i])
{
DebugBreak();
}
}
}
//解同余方程 x + a ≡ val(mod 0xff8f)
static long long congruence_add(unsigned short a, unsigned short val)
{
long long v = val;
v -= a;
if (v < 0)
v += 0xff8f;
assert(v <= MAXUINT16);
return v;
}
//解同余方程 x - a ≡ val(mod 0xff8f)
static long long congruence_sub(long long a, long long val)
{
long long v = val;
v += a;
v %= 0xff8f;
/*if (v >= 0xff8f)
v -= 0xff8f;*/
assert(v <= MAXUINT16);
return v;
}
//解同余方程 x * a ≡ val(mod 0xff8f)
static long long congruence_mul(long long a, long long val)
{
//x * 0x26c0 ≡ val(mod 0xff8f)
long long v = val;
while (v % a != 0)
{
v += 0xff8f;
}
assert(v <= MAXULONG32);
return (unsigned short)((unsigned long)v / a);
}
//加密盒转换
static long long __transform_box(const unsigned char boxin[0x3700], unsigned char boxout[0x3700], int level)
{
//原始算法模拟
/*for (int m = 0; m < 16; m++)
{
long long* p = (long long*)(box + 0x370 * m);
for (int n = m + 1; n < 16; n++)
{
long long* q = (long long*)(box + 0x370 * n);
long long c = q[m];
for (int i = m; i < 17; i++)
{
long long s = q[i] * p[m] - p[i] * c;
s %= 0xff8f;
if (s < 0) s += 0xff8f;
q[i] = s;
}
}
}*/
long long c = 0;
memcpy(boxout, boxin, 0x3700);
for (int m = 0; m < level; m++)
{
long long* p = (long long*)(boxout + 0x370 * m);
for (int n = m + 1; n < 16; n++)
{
long long* q = (long long*)(boxout + 0x370 * n);
c = q[m];
for (int i = m; i < 17; i++)
{
long long s = q[i] * p[m] - p[i] * c;
s %= 0xff8f;
if (s < 0) s += 0xff8f;
q[i] = s;
}
}
}
return c;
}
//解码
static void decode(const unsigned char bufin[16], unsigned short bufout[16])
{
//
unsigned char *box = new unsigned char[0x3700];
unsigned char *box2 = new unsigned char[0x3700];
if (!box || !box2)
{
cout << "error: alloc memory failed." << endl;
return;
}
//读取缓存的计算数据
ifstream f("1.bin", ifstream::binary | ifstream::in);
if (!f || !f.read((char*)box, 0x3700))
{
cout << "error: read file data failed." << endl;
delete[]box;
delete[]box2;
return;
}
f.close();
//计算中间值
unsigned short key[16] = { 0xd6dc, 0xd613, 0x66cd, 0x332e, 0x9932, 0x5db8, 0x1731, 0xacde, 0x3c5a, 0x4d87, 0xbeb1, 0xb5bb, 0x125f, 0x2526, 0xdc64, 0x26c0 };
unsigned short mid[16] = { 0 };
for (int i = 15; i >= 0; i--)
{
mid[i] = (unsigned short)congruence_mul(key[i], bufin[i]);
}
for (int m = 0; m < 16; m++)
{
long long* p = (long long*)(box + 0x370 * m);
long long s = mid[m];
for (int i = 15; i >= m + 1; i--)
{
assert(p[i] <= MAXUINT16);
long long ll = p[i] * bufin[i];
s = congruence_sub(ll, s);
//cout << hex << s << endl;
}
mid[m] = (unsigned short)s;
//cout << hex << s << " " << p[16] << endl;
}
//计算原始值
f.open("0.bin", ifstream::binary | ifstream::in);
if (!f || !f.read((char*)box, 0x3700))
{
cout << "error: read file data failed." << endl;
delete[]box;
return;
}
f.close();
for (int i = 0; i < 16; i++)
{
long long m = mid[i];
long long last = 0;
if (i > 0)
last = mid[i - 1];
for (int lev = i; lev > 0; lev--)
{
auto c = __transform_box(box, box2, lev - 1);
long long* p = (long long*)(box2 + 0x370 * (lev - 1));
long long* q = (long long*)(box2 + 0x370 * i);
m = congruence_sub(mid[lev - 1] * q[lev - 1], m);
m = congruence_mul(p[lev - 1], m);
last = m;
}
bufout[i] = (unsigned short)m;
}
delete[]box;
delete[]box2;
}
//校验
static void encrypt_verify(unsigned char buf1[16], unsigned char buf2[16])
{
unsigned char k1[16] =
{
0x1A, 0x1C, 0x11, 0x18, 0x08, 0x0C, 0x19, 0x01, 0x20, 0x0B, 0x07, 0x10, 0x17, 0x02, 0x1D, 0x15,
};
unsigned char k2[16] =
{
0x15, 0x17, 0x16, 0x14, 0x13, 0x0C, 0x04, 0x12, 0x03, 0x06, 0x10, 0x0E, 0x0A, 0x18, 0x1C, 0x0F,
};
unsigned char k3[16] =
{
0x03, 0xEE, 0xEC, 0x11, 0x14, 0x0E, 0x05, 0x0C, 0x03, 0xED, 0xF7, 0x05, 0x00, 0xF6, 0x00, 0xE7,
};
unsigned char out[16] = { 0 };
for (size_t i = 0; i < 16; i++)
{
unsigned char c = buf1[i];
c ^= k2[i];
unsigned char r = (unsigned char)(k1[i] & 7);
__asm
{
mov al, c
mov cl, r
ror al, cl
mov c, al
}
c += (k3[i] - buf2[i]);
out[i] = c;
}
}
static void decrypt_verify(unsigned char buf[16])
{
const unsigned char act[16] =
{
0x15, 0x09, 0x0C, 0x1F, 0x1C, 0x13, 0x16, 0x19, 0x1D, 0x03, 0x10, 0x0F, 0x01, 0x02, 0x1E, 0x06,
};
unsigned char k1[16] =
{
0x1A, 0x1C, 0x11, 0x18, 0x08, 0x0C, 0x19, 0x01, 0x20, 0x0B, 0x07, 0x10, 0x17, 0x02, 0x1D, 0x15,
};
unsigned char k2[16] =
{
0x15, 0x17, 0x16, 0x14, 0x13, 0x0C, 0x04, 0x12, 0x03, 0x06, 0x10, 0x0E, 0x0A, 0x18, 0x1C, 0x0F,
};
unsigned char k3[16] =
{
0x03, 0xEE, 0xEC, 0x11, 0x14, 0x0E, 0x05, 0x0C, 0x03, 0xED, 0xF7, 0x05, 0x00, 0xF6, 0x00, 0xE7,
};
//unsigned char out[16] = { 0 };
for (size_t i = 0; i < 16; i++)
{
unsigned char c = act[i];
c -= (k3[i] - buf[i]);
unsigned char r = (unsigned char)(k1[i] & 7);
__asm
{
mov al, c
mov cl, r
rol al, cl
mov c, al
}
c ^= k2[i];
buf[i] = c;
}
}
void alg_1(unsigned char seri[0x20])
{
unsigned char seri_d[16] =
{
0x51, 0x0B, 0x3D, 0x82, 0xCB, 0x55, 0x77, 0xB5, 0xDC, 0x1A, 0x90, 0x82, 0x33, 0xC1, 0x2A, 0x36,
};
decrypt(seri_d);
cout << "STEP_1A:" << endl;
for (size_t i = 0; i < 16; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)seri_d[i] << " " << flush;
}
cout << endl;
unsigned char seri_dl[0x20] = { 0 };
dilate(seri_d, seri_dl);
cout << "STEP_2A:" << endl;
for (size_t i = 0; i < 0x20; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)seri_dl[i] << " " << flush;
}
cout << endl;
aes_dec(seri_dl);
cout << "STEP_3A:" << endl;
for (size_t i = 0; i < 0x20; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)seri_dl[i] << " " << flush;
}
cout << endl;
vm_decode(seri_dl);
cout << "STEP_4A:" << endl;
for (size_t i = 0; i < 0x20; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)seri_dl[i] << " " << flush;
}
cout << endl;
memcpy(seri, seri_dl, 0x20);
}
void alg_2(unsigned char seri[0xc0])
{
unsigned char seri_d[16] = { 0xF5, 0x0B, 0xAB, 0xE1, 0x20, 0x7E, 0x50, 0x75, 0x31, 0x2B, 0x89, 0x60, 0xC1, 0x9E, 0xF1, 0x44, };
decrypt(seri_d);
cout << "STEP_1B:" << endl;
for (size_t i = 0; i < 16; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)seri_d[i] << " " << flush;
}
cout << endl;
unsigned short seri_s[16] = { 0 };
decode(seri_d, seri_s);
cout << "STEP_2B:" << endl;
for (size_t i = 0; i < 16 * 2; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)((unsigned char*)seri_s)[i] << " " << flush;
}
cout << endl;
unsigned char seri_c[0xc0] = { 0 };
dilate((unsigned char*)seri_s, seri_c);
cout << "STEP_3B:" << endl;
for (size_t i = 0; i < 0xc0; i++)
{
cout << setw(2) << setfill('0') << right << hex << (int)seri_c[i] << " " << flush;
if ((i + 1) % 0x20 == 0)
{
cout << endl;
}
}
cout << endl;
memcpy(seri, seri_c, 0xc0);
}
int main()
{
unsigned char seri[0xe0] = { 0 };
alg_2(seri + 0x20);
alg_1(seri);
ostringstream oss;
for (size_t i = 0; i < 0xe0; i++)
{
oss << setw(2) << hex << setfill('0') << right << (int)seri[i] << flush;
}
cout << "INPUT:" << endl << oss.str() << endl;
cin.get();
return 0;
}
看完解析你会了吗?你还有不一样的解题思路吗? 实践出真知~速速动手自己做一遍,才算把知识装进脑子~ 欢迎大家分享解题思路哦~
现在第九题《命悬一线》正在火热进行中!
有你比赛更精彩!
越早提交答案,得分越高哦!
立即扫码加入战斗!
赛题回顾
出题战队:七星战队
出题战队:中娅之戒
出题战队:2019
出题战队:大灰狼爱喜羊羊
出题战队:金左手
出题团队:T.O.
出题团队:HU1战队
你的好友秀秀子拍了拍你
并请你点击阅读原文,参与最新一题的挑战!