Reverse Engineering
Last updated
Last updated
Challenge | Link |
---|---|
Let's just deal with them one by one, shall we?
Given PE32+ executable, open it using IDA
We can see that there are some unknown function such as sub_140001020 and sub_140001000. Take a look on each function we can know what is those function do
To help us carry out static analysis, we rename those function.
We can see the program receive our input on line 28 using scanf function, but there is a function that executed before our input received which is sub_140001480.
Function sub_140001480 is custom function and the result from that function is static.
So basically we can dump the values and use it for next step without reimplement the function. After receiving our input, the program processed our input with custom algorithm again.
----SNIPPET----
v7 = input + 3;
v8 = 2i64;
do
{
*(v7 - 3) ^= *(v7 - 3) >> 12;
*(v7 - 2) ^= *(v7 - 2) >> 12;
*(v7 - 1) ^= *(v7 - 1) >> 12;
*v7 ^= *v7 >> 12;
v7[1] ^= v7[1] >> 12;
v7[2] ^= v7[2] >> 12;
v7[3] ^= v7[3] >> 12;
v7[4] ^= v7[4] >> 12;
v7[5] ^= v7[5] >> 12;
v7[6] ^= v7[6] >> 12;
v7[7] ^= v7[7] >> 12;
v7[8] ^= v7[8] >> 12;
v7[9] ^= v7[9] >> 12;
v7[10] ^= v7[10] >> 12;
v7[11] ^= v7[11] >> 12;
v7[12] ^= v7[12] >> 12;
v7[13] ^= v7[13] >> 12;
v7[14] ^= v7[14] >> 12;
v7[15] ^= v7[15] >> 12;
v7[16] ^= v7[16] >> 12;
v7[17] ^= v7[17] >> 12;
v7[18] ^= v7[18] >> 12;
v7[19] ^= v7[19] >> 12;
v7[20] ^= v7[20] >> 12;
v9 = v7[21];
v7 += 32;
*(v7 - 11) = v9 ^ (v9 >> 12);
*(v7 - 10) ^= *(v7 - 10) >> 12;
*(v7 - 9) ^= *(v7 - 9) >> 12;
*(v7 - 8) ^= *(v7 - 8) >> 12;
*(v7 - 7) ^= *(v7 - 7) >> 12;
*(v7 - 6) ^= *(v7 - 6) >> 12;
*(v7 - 5) ^= *(v7 - 5) >> 12;
*(v7 - 4) ^= *(v7 - 4) >> 12;
--v8;
}
----SNIPPET----
So there is little obfuscation regarding the index of input, but we can easily analyze it
v7 = input + 3;
*(v7 - 3) ^= *(v7 - 3) >> 12; // (input + 3 - 3) = input + 0
*(v7 - 2) ^= *(v7 - 2) >> 12; // (input + 3 - 2) = input + 1
*(v7 - 1) ^= *(v7 - 1) >> 12; // (input + 3 - 2) = input + 2
...
v9 = v7[21];
v7 += 32;
*(v7 - 11) = v9 ^ (v9 >> 12); // input + 3 + 32 - 11 = input + 24
*(v7 - 10) ^= *(v7 - 10) >> 12; // input + 3 + 32 - 10 = input + 25
So basically it loop from index 0 until index 31 (32 iteration), but since v8 value is 2 so it do iteration for index 0 until index 63 (64 iteration). Here is the implementation on python.
for i in range(0, len(v7), 32):
for j in range(32):
v7[i+j] ^= v7[i+j] >> 12
Next, we take a look on function sub_1400010E0.
sub_1400010E0(v3, (__int64)v7, (__int64)input, (__int64)Buf1);
LODWORD(v4) = *a1;
v5 = (_BYTE *)(a4 + 2);
LODWORD(v6) = a1[1];
v7 = (_BYTE *)(a3 + 2);
v8 = a4 - a3;
v10 = 32i64;
do
{
v11 = (unsigned __int8)(v4 + 1);
v12 = a1[v11 + 2];
v13 = (unsigned __int8)(v12 + v6);
v14 = a1[v13 + 2];
a1[v11 + 2] = v14;
a1[v13 + 2] = v12;
v7[v8 - 2] = *(v7 - 2) ^ LOBYTE(a1[(unsigned __int8)(v12 + v14) + 2]);
v15 = (unsigned __int8)(v11 + 1);
v16 = a1[v15 + 2];
v17 = (unsigned __int8)(v13 + v16);
v18 = a1[v17 + 2];
a1[v15 + 2] = v18;
a1[v17 + 2] = v16;
*(v5 - 1) = *(v7 - 1) ^ LOBYTE(a1[(unsigned __int8)(v16 + v18) + 2]);
v19 = (unsigned __int8)(v15 + 1);
v20 = a1[v19 + 2];
v21 = (unsigned __int8)(v17 + v20);
v22 = a1[v21 + 2];
a1[v19 + 2] = v22;
a1[v21 + 2] = v20;
*v5 = *v7 ^ LOBYTE(a1[(unsigned __int8)(v20 + v22) + 2]);
v23 = (unsigned __int8)(v19 + 1);
v24 = a1[v23 + 2];
v25 = (unsigned __int8)(v21 + v24);
v26 = a1[v25 + 2];
a1[v23 + 2] = v26;
a1[v25 + 2] = v24;
v5[1] = v7[1] ^ LOBYTE(a1[(unsigned __int8)(v24 + v26) + 2]);
v27 = (unsigned __int8)(v23 + 1);
v28 = a1[v27 + 2];
v29 = (unsigned __int8)(v25 + v28);
v30 = a1[v29 + 2];
a1[v27 + 2] = v30;
a1[v29 + 2] = v28;
v5[2] = v7[2] ^ LOBYTE(a1[(unsigned __int8)(v28 + v30) + 2]);
v31 = (unsigned __int8)(v27 + 1);
v32 = a1[v31 + 2];
v33 = (unsigned __int8)(v29 + v32);
v34 = a1[v33 + 2];
a1[v31 + 2] = v34;
a1[v33 + 2] = v32;
v5[3] = v7[3] ^ LOBYTE(a1[(unsigned __int8)(v32 + v34) + 2]);
v35 = (unsigned __int8)(v31 + 1);
v36 = a1[v35 + 2];
v37 = (unsigned __int8)(v33 + v36);
v38 = a1[v37 + 2];
a1[v35 + 2] = v38;
a1[v37 + 2] = v36;
v5[4] = v7[4] ^ LOBYTE(a1[(unsigned __int8)(v36 + v38) + 2]);
v39 = (unsigned __int8)(v35 + 1);
v40 = a1[v39 + 2];
v41 = (unsigned __int8)(v37 + v40);
v42 = a1[v41 + 2];
a1[v39 + 2] = v42;
a1[v41 + 2] = v40;
v5[5] = v7[5] ^ LOBYTE(a1[(unsigned __int8)(v40 + v42) + 2]);
v43 = (unsigned __int8)(v39 + 1);
v44 = a1[v43 + 2];
v45 = (unsigned __int8)(v41 + v44);
v46 = a1[v45 + 2];
a1[v43 + 2] = v46;
a1[v45 + 2] = v44;
v5[6] = v7[6] ^ LOBYTE(a1[(unsigned __int8)(v44 + v46) + 2]);
v47 = (unsigned __int8)(v43 + 1);
v48 = a1[v47 + 2];
v49 = (unsigned __int8)(v45 + v48);
v50 = a1[v49 + 2];
a1[v47 + 2] = v50;
a1[v49 + 2] = v48;
v5[7] = v7[7] ^ LOBYTE(a1[(unsigned __int8)(v48 + v50) + 2]);
v51 = (unsigned __int8)(v47 + 1);
v52 = a1[v51 + 2];
v53 = (unsigned __int8)(v49 + v52);
v54 = a1[v53 + 2];
a1[v51 + 2] = v54;
a1[v53 + 2] = v52;
v5[8] = v7[8] ^ LOBYTE(a1[(unsigned __int8)(v52 + v54) + 2]);
v55 = (unsigned __int8)(v51 + 1);
v56 = a1[v55 + 2];
v57 = (unsigned __int8)(v53 + v56);
v58 = a1[v57 + 2];
a1[v55 + 2] = v58;
a1[v57 + 2] = v56;
v5[9] = v7[9] ^ LOBYTE(a1[(unsigned __int8)(v56 + v58) + 2]);
v59 = (unsigned __int8)(v55 + 1);
v60 = a1[v59 + 2];
v61 = (unsigned __int8)(v57 + v60);
v62 = a1[v61 + 2];
a1[v59 + 2] = v62;
v5 += 16;
a1[v61 + 2] = v60;
v7 += 16;
*(v5 - 6) = *(v7 - 6) ^ LOBYTE(a1[(unsigned __int8)(v60 + v62) + 2]);
v63 = (unsigned __int8)(v59 + 1);
v64 = a1[v63 + 2];
v65 = (unsigned __int8)(v61 + v64);
v66 = a1[v65 + 2];
a1[v63 + 2] = v66;
a1[v65 + 2] = v64;
*(v5 - 5) = *(v7 - 5) ^ LOBYTE(a1[(unsigned __int8)(v64 + v66) + 2]);
v67 = (unsigned __int8)(v63 + 1);
v68 = a1[v67 + 2];
v69 = (unsigned __int8)(v65 + v68);
v70 = a1[v69 + 2];
a1[v67 + 2] = v70;
a1[v69 + 2] = v68;
*(v5 - 4) = *(v7 - 4) ^ LOBYTE(a1[(unsigned __int8)(v68 + v70) + 2]);
v4 = (unsigned __int8)(v67 + 1);
v71 = a1[v4 + 2];
v6 = (unsigned __int8)(v69 + v71);
v72 = a1[v6 + 2];
a1[v4 + 2] = v72;
a1[v6 + 2] = v71;
result = *(v7 - 3) ^ LOBYTE(a1[(unsigned __int8)(v71 + v72) + 2]);
*(v5 - 3) = result;
--v10;
}
while ( v10 );
a1[1] = v6;
*a1 = v4;
return result;
The algorithm has pattern, so we just need to deobfuscate the first part then just loop the rest.
// a1 = generated_values from sub_140001480
LODWORD(v4) = *a1; // a1[0] == 0
v5 = (_BYTE *)(a4 + 2); // result_address (stored processed input)
LODWORD(v6) = a1[1]; // a1[1] == 0
v7 = (_BYTE *)(a3 + 2);
v8 = a4 - a3;
v10 = 32i64;
do {
v11 = (unsigned __int8)(v4 + 1); // 0 + 1 = 1
v12 = a1[v11 + 2]; // a1[1+2] = a1[3]
v13 = (unsigned __int8)(v12 + v6); // a1[3] + 0 = a1[3]
v14 = a1[v13 + 2]; // a1[a1[3] + 2]
a1[v11 + 2] = v14; // a1[1] = v14
a1[v13 + 2] = v12; // a1[a1[3]] = v12
v7[v8 - 2] = *(v7 - 2) ^ LOBYTE(a1[(unsigned __int8)(v12 + v14) + 2]); // result_address[0] = processed_input[0] ^ a1[a1[3] + a1[a1[3] + 2] + 2]
...
To validate the last part (xor part), we can debug the executable and breakpoint on instruction below
00007FF7293A113C: xor al, [r11-2]
After we know how the algorithm processed our input and static values now we just need to reimplement it on python
def sub_7FF671F610E0(a1, a2):
v4 = a1[0]
v6 = a1[1]
v5 = []
for i in range(32):
for j in range(16):
v4 += 1
v4 &= 0xff
v12 = a1[v4+2]
v6 += v12
v6 &= 0xff
v14 = a1[v6+2]
a1[v4+2] = v14
a1[v6+2] = v12
v5.append(a2[i][j] ^ a1[((v12 + v14)&0xff) + 2])
return v5
Back to main function, returned values from sub_7FF7293A10E0 processed with the same algorithm like previous part.
----SNIPPET----
*((_QWORD *)v10 - 3) ^= *((_QWORD *)v10 - 3) >> 12;
*((_QWORD *)v10 - 2) ^= *((_QWORD *)v10 - 2) >> 12;
*((_QWORD *)v10 - 1) ^= *((_QWORD *)v10 - 1) >> 12;
*(_QWORD *)v10 ^= *(_QWORD *)v10 >> 12;
*((_QWORD *)v10 + 1) ^= *((_QWORD *)v10 + 1) >> 12;
*((_QWORD *)v10 + 2) ^= *((_QWORD *)v10 + 2) >> 12;
*((_QWORD *)v10 + 3) ^= *((_QWORD *)v10 + 3) >> 12;
*((_QWORD *)v10 + 4) ^= *((_QWORD *)v10 + 4) >> 12;
*((_QWORD *)v10 + 5) ^= *((_QWORD *)v10 + 5) >> 12;
*((_QWORD *)v10 + 6) ^= *((_QWORD *)v10 + 6) >> 12;
*((_QWORD *)v10 + 7) ^= *((_QWORD *)v10 + 7) >> 12;
*((_QWORD *)v10 + 8) ^= *((_QWORD *)v10 + 8) >> 12;
*((_QWORD *)v10 + 9) ^= *((_QWORD *)v10 + 9) >> 12;
*((_QWORD *)v10 + 10) ^= *((_QWORD *)v10 + 10) >> 12;
*((_QWORD *)v10 + 11) ^= *((_QWORD *)v10 + 11) >> 12;
*((_QWORD *)v10 + 12) ^= *((_QWORD *)v10 + 12) >> 12;
----SNIPPET----
Since we've reimplement it on python we can reuse the code. Here is the final script to implement the whole algorithm.
from Crypto.Util.number import *
import string
def print_hex(inp):
arr = []
for i in inp:
arr.append(hex(i))
print(arr)
def make_block(inp):
blocks = []
for i in range(0, len(inp), 8):
blocks.append(bytes_to_long(inp[i:i+8]))
return blocks
def make_byte(inp):
arr = []
for i in range(len(inp)):
tmp = long_to_bytes(inp[i])[::-1]
for j in range(len(tmp)):
arr.append(tmp[j])
return arr
def combine_16(inp):
arr = []
for i in range(0, len(inp), 2):
tmp = long_to_bytes(inp[i])[::-1]
tmp += long_to_bytes(inp[i+1])[::-1]
arr.append(tmp)
return arr
def combine_8(inp):
arr = []
for i in range(0, len(inp), 8):
arr.append(bytes_to_long(bytes(inp[i:i+8])[::-1]))
return arr
def sub_7FF671F610E0(a1, a2):
v4 = a1[0]
v6 = a1[1]
v5 = []
for i in range(32):
for j in range(16):
v4 += 1
v4 &= 0xff
v12 = a1[v4+2]
v6 += v12
v6 &= 0xff
v14 = a1[v6+2]
a1[v4+2] = v14
a1[v6+2] = v12
v5.append(a2[i][j] ^ a1[((v12 + v14)&0xff) + 2])
return v5
dk = [0x0,0x0,0x32,0x63,0x4F,0x6A,0x61,0x0B,0x0D7,0x31,0x76,0x29,0x0C,0x69,0x21,0x93,0x1C,0x2B,0x0E9,0x0B6,0x0AA,0x3C,0x0CA,0x7,0x9B,0x54,0x58,0x6,0x0ED,0x96,0x89,0x0C7,0x0F9,0x66,0x0B8,0x92,0x82,0x17,0x19,0x1D,0x0A9,0x30,0x0FC,0x0E4,0x0F7,0x33,0x5C,0x0BB,0x8C,0x7A,0x0DD,0x38,0x48,0x0CD,0x1,0x1B,0x0B3,0x0DE,0x0,0x15,0x0CE,0x43,0x3,0x7E,0x36,0x7D,0x23,0x73,0x6B,0x0B1,0x46,0x52,0x59,0x3D,0x7F,0x5B,0x78,0x9F,0x85,0x4A,0x20,0x97,0x9A,0x1F,0x77,0x0AB,0x28,0x72,0x0CB,0x81,0x0CC,0x0EB,0x0D2,0x0B9,0x2D,0x12,0x13,0x0C0,0x0A6,0x25,0x71,0x0A,0x88,0x9E,0x37,0x22,0x24,0x47,0x42,0x0A5,0x0FA,0x2A,0x53,0x8A,0x6C,0x99,0x9,0x0E3,0x0EF,0x0EC,0x0E0,0x0A0,0x51,0x0F3,0x1E,0x4,0x8F,0x0E7,0x2,0x0A1,0x90,0x60,0x0A4,0x0AD,0x0FD,0x5F,0x79,0x44,0x6E,0x39,0x34,0x4C,0x0A3,0x0D4,0x74,0x0B4,0x9C,0x8E,0x83,0x0E6,0x4E,0x0D5,0x3A,0x0F1,0x0BE,0x6D,0x5,0x0BA,0x84,0x0B2,0x87,0x10,0x0F4,0x0BC,0x0D8,0x0FE,0x0AE,0x0BD,0x7C,0x0C3,0x0E8,0x0E5,0x4B,0x0C9,0x2C,0x0B5,0x3F,0x4D,0x50,0x0BF,0x8D,0x45,0x0C8,0x18,0x0F0,0x0DA,0x8B,0x0DB,0x0C4,0x16,0x8,0x0F,0x62,0x0D6,0x91,0x1A,0x0A8,0x9D,0x0D1,0x98,0x86,0x67,0x0C5,0x68,0x0C6,0x35,0x0AF,0x0EA,0x0F8,0x0C2,0x0D0,0x56,0x94,0x40,0x0FF,0x26,0x65,0x2E,0x0D9,0x49,0x57,0x5D,0x0AC,0x0A2,0x0B0,0x0D,0x0F6,0x0C1,0x0EE,0x0FB,0x55,0x6F,0x0A7,0x0DC,0x75,0x0E,0x64,0x14,0x0DF,0x95,0x0CF,0x3E,0x0F2,0x0F5,0x41,0x0D3,0x0E2,0x0B7,0x80,0x3B,0x27,0x7B,0x5E,0x0E1,0x2F,0x5A,0x70,0x11,0x0ABABABAB,0x0ABABABAB,0x0ABABABAB,0x0ABABABAB,0x0FEEEFEEE,0x0FEEEFEEE,0x0,0x0,0x0,0x0]
cmp_val = [ 0x07, 0x56, 0xE5, 0x58, 0x71, 0x89, 0x9A, 0xCA, 0xF0, 0x67,
0x03, 0x2D, 0x49, 0xFB, 0x6E, 0x86, 0xC2, 0xF7, 0x48, 0xCA,
0x3C, 0x43, 0xDB, 0x8E, 0x04, 0x2A, 0x56, 0x4A, 0x97, 0x33,
0xA1, 0xA2, 0x07, 0x83, 0xF0, 0x89, 0x19, 0x13, 0x77, 0xB4,
0x9F, 0x7D, 0x7B, 0x9C, 0xDD, 0x8E, 0xFD, 0xAD, 0xB5, 0xE2,
0x28, 0x0E, 0x06, 0xAF, 0xE5, 0xE3, 0x86, 0xC3, 0x08, 0xAD,
0xE6, 0x4C, 0xDE, 0x63, 0xA3, 0x5F, 0x1E, 0x96, 0x34, 0x7D,
0x9D, 0x19, 0xF5, 0xC8, 0x84, 0x7F, 0x7B, 0x62, 0x2A, 0x6B,
0xC1, 0x28, 0x3B, 0x6D, 0x09, 0xEF, 0xFC, 0xCB, 0xA0, 0x90,
0x9A, 0x3E, 0x66, 0xA2, 0x4E, 0x06, 0x90, 0x2C, 0x9D, 0xAE,
0x3C, 0x99, 0x40, 0x53, 0x4C, 0x69, 0x63, 0xE7, 0xB9, 0xA8,
0xB3, 0x87, 0xA5, 0x97, 0x98, 0xFE, 0x1F, 0x20, 0x51, 0xA7,
0xAE, 0x0D, 0x00, 0xAB, 0x16, 0x35, 0x59, 0x3D, 0x08, 0x1B,
0x1C, 0x92, 0xE2, 0x4F, 0x1D, 0x86, 0xA5, 0x6E, 0x0A, 0x14,
0x45, 0x4D, 0x61, 0x08, 0x69, 0xC3, 0x12, 0xA2, 0xEB, 0x50,
0x13, 0x93, 0x22, 0xE2, 0xC4, 0x10, 0xCA, 0x5F, 0xB2, 0x0B,
0xA2, 0x30, 0xC8, 0x54, 0x91, 0x3A, 0x37, 0xFD, 0xD2, 0x10,
0xAB, 0x5A, 0xF8, 0x38, 0xF3, 0xD3, 0xD5, 0x85, 0x58, 0xDE,
0xDF, 0xC0, 0xF4, 0x17, 0x4E, 0xF7, 0x31, 0x79, 0xDD, 0x41,
0x2F, 0xB3, 0x20, 0xC7, 0xEC, 0x98, 0x5E, 0xAE, 0xF7, 0xA9,
0xCB, 0x27, 0x13, 0x72, 0xFE, 0xCA, 0x64, 0xFF, 0x43, 0x93,
0x80, 0x3E, 0x1E, 0xE5, 0x99, 0xBF, 0x41, 0x4B, 0x9D, 0x85,
0x4E, 0x0F, 0x99, 0x94, 0x57, 0xE1, 0x63, 0xD9, 0x01, 0x85,
0x78, 0x8A, 0x06, 0xFE, 0x9D, 0x41, 0x32, 0x74, 0x55, 0x83,
0xB2, 0x85, 0xE9, 0x9F, 0xC6, 0x2C, 0x4B, 0x62, 0x8F, 0xBF,
0x7D, 0x57, 0xC8, 0x76, 0x3B, 0x31, 0x5E, 0x87, 0x60, 0x89,
0x35, 0x41, 0xC1, 0x52, 0x6C, 0xD0, 0x0B, 0x7D, 0xCA, 0x60,
0x5D, 0x82, 0x19, 0xB0, 0x96, 0x5E, 0x16, 0xE7, 0x9B, 0x2F,
0x37, 0x5F, 0xC9, 0xC5, 0xF3, 0x20, 0xC3, 0x45, 0xCB, 0x47,
0xA1, 0xCC, 0x79, 0xE5, 0xB6, 0xFB, 0xD4, 0x55, 0xDB, 0xC1,
0x35, 0x9B, 0x8B, 0xFA, 0x38, 0xD5, 0xB2, 0xB5, 0xE0, 0x4F,
0x4D, 0x6C, 0x4F, 0x8C, 0x0C, 0x42, 0xBC, 0x8E, 0xB3, 0x78,
0x48, 0xE4, 0x87, 0x8E, 0x34, 0xA3, 0x1D, 0x01, 0x53, 0x98,
0x71, 0xFA, 0x8F, 0x2F, 0xE3, 0x7A, 0x6B, 0xB9, 0x1B, 0xB6,
0x7E, 0x34, 0x7F, 0xC8, 0xC4, 0x6C, 0xAB, 0x45, 0x4D, 0x81,
0xEF, 0xEE, 0xC3, 0xD9, 0xDB, 0x13, 0x5B, 0x63, 0x90, 0xFC,
0x34, 0x18, 0x81, 0xBC, 0xD1, 0x18, 0x48, 0xBB, 0x7C, 0x24,
0x5B, 0x56, 0x2B, 0x35, 0x6B, 0xD7, 0xF9, 0xD3, 0xD5, 0x2B,
0xE2, 0x24, 0xD8, 0x50, 0xF1, 0xEC, 0xD5, 0xE6, 0x29, 0x55,
0x66, 0xF2, 0xF7, 0x28, 0x20, 0x7D, 0xF3, 0x47, 0x40, 0x03,
0x11, 0x4A, 0x47, 0xA5, 0xB4, 0x74, 0x15, 0x35, 0xD0, 0xF0,
0xE5, 0x4C, 0x04, 0xB5, 0x59, 0xFE, 0xFC, 0x45, 0x9D, 0x3A,
0xA1, 0x3F, 0x1A, 0xA7, 0xA8, 0x51, 0xE5, 0x65, 0xF1, 0x56,
0xEE, 0xDE, 0xFC, 0xC4, 0x87, 0xF5, 0xFA, 0x79, 0x31, 0x07,
0x0A, 0x3F, 0x41, 0x28, 0xD1, 0x59, 0x17, 0x4D, 0x02, 0xE4,
0x5A, 0x22, 0x3A, 0xBC, 0xD2, 0xCD, 0x80, 0xBC, 0x2A, 0x49,
0xF0, 0x7F, 0x97, 0xA1, 0x90, 0x59, 0x01, 0x8D, 0x25, 0x43,
0xD8, 0x00, 0xEA, 0xD8, 0x4F, 0xE2, 0x4E, 0x2B, 0x06, 0xFD,
0x7E, 0x16, 0xA9, 0x92, 0xC4, 0xFD, 0xB5, 0x6A, 0x82, 0x06,
0x18, 0x0C, 0x0A, 0xB7, 0xB8, 0x29, 0x8F, 0x87, 0x63, 0x65,
0x25, 0xB9, 0x7A, 0xD0, 0x6E, 0x30, 0x3C, 0xF2, 0xF7, 0xC2,
0x30, 0x86]
inp = b""
for i in string.printable[:64]:
inp += (i*8).encode()
print(inp)
v7 = make_block(inp)
for i in range(0, len(v7), 32):
for j in range(32):
v7[i+j] ^= v7[i+j] >> 12
v7_16 = combine_16(v7)
v10 = sub_7FF671F610E0(dk, v7_16)
v10_8 = combine_8(v10)
for i in range(0, len(v10_8), 32):
for j in range(32):
v10_8[i+j] ^= v10_8[i+j] >> 12
res = make_byte(v10_8)
print_hex(res)
Now, we assume that those algorhtm encrypt our input. So the next step we do is figuring out how to implement the decryption routine.
sub_7FF671F610E0
Encryption routine : xor processed input (a2) with static values (a1/SBOX)
Decyption routine : xor processed input (a2) with static values (a1/SBOX)
Xor shift part
Encryption routine : the algorithm looks like grey code but with shift 12
Decryption routine : implement rev grey code with shift 12 (https://github.com/hellman/libnum/blob/master/libnum/stuff.py#L10)
Last step just implement decryption routine with above information then decrypt ciphertext of flag. Here is the implementation in python.
from Crypto.Util.number import *
import string
def print_hex(inp):
arr = []
for i in inp:
arr.append(hex(i))
print(arr)
def make_block(inp):
blocks = []
for i in range(0, len(inp), 8):
blocks.append(bytes_to_long(inp[i:i+8]))
return blocks
def make_byte(inp):
arr = []
for i in range(len(inp)):
tmp = long_to_bytes(inp[i])[::-1]
for j in range(len(tmp)):
arr.append(tmp[j])
return arr
def combine_16(inp):
arr = []
for i in range(0, len(inp), 2):
tmp = long_to_bytes(inp[i]).rjust(8, b"\x00")[::-1]
tmp += long_to_bytes(inp[i+1]).rjust(8, b"\x00")[::-1]
arr.append(tmp)
return arr
def combine_8(inp):
arr = []
for i in range(0, len(inp), 8):
arr.append(bytes_to_long(bytes(inp[i:i+8])[::-1]))
return arr
def sub_7FF671F610E0(a1, a2):
v4 = a1[0]
v6 = a1[1]
v5 = []
for i in range(32):
for j in range(16):
v4 += 1
v4 &= 0xff
v12 = a1[v4+2]
v6 += v12
v6 &= 0xff
v14 = a1[v6+2]
a1[v4+2] = v14
a1[v6+2] = v12
v5.append(a2[i][j] ^ a1[((v12 + v14)&0xff) + 2])
return v5
def rev_shift(g):
n = 0
while g:
n ^= g
g >>= 12
return n
res = [ 0x07, 0x56, 0xE5, 0x58, 0x71, 0x89, 0x9A, 0xCA, 0xF0, 0x67,
0x03, 0x2D, 0x49, 0xFB, 0x6E, 0x86, 0xC2, 0xF7, 0x48, 0xCA,
0x3C, 0x43, 0xDB, 0x8E, 0x04, 0x2A, 0x56, 0x4A, 0x97, 0x33,
0xA1, 0xA2, 0x07, 0x83, 0xF0, 0x89, 0x19, 0x13, 0x77, 0xB4,
0x9F, 0x7D, 0x7B, 0x9C, 0xDD, 0x8E, 0xFD, 0xAD, 0xB5, 0xE2,
0x28, 0x0E, 0x06, 0xAF, 0xE5, 0xE3, 0x86, 0xC3, 0x08, 0xAD,
0xE6, 0x4C, 0xDE, 0x63, 0xA3, 0x5F, 0x1E, 0x96, 0x34, 0x7D,
0x9D, 0x19, 0xF5, 0xC8, 0x84, 0x7F, 0x7B, 0x62, 0x2A, 0x6B,
0xC1, 0x28, 0x3B, 0x6D, 0x09, 0xEF, 0xFC, 0xCB, 0xA0, 0x90,
0x9A, 0x3E, 0x66, 0xA2, 0x4E, 0x06, 0x90, 0x2C, 0x9D, 0xAE,
0x3C, 0x99, 0x40, 0x53, 0x4C, 0x69, 0x63, 0xE7, 0xB9, 0xA8,
0xB3, 0x87, 0xA5, 0x97, 0x98, 0xFE, 0x1F, 0x20, 0x51, 0xA7,
0xAE, 0x0D, 0x00, 0xAB, 0x16, 0x35, 0x59, 0x3D, 0x08, 0x1B,
0x1C, 0x92, 0xE2, 0x4F, 0x1D, 0x86, 0xA5, 0x6E, 0x0A, 0x14,
0x45, 0x4D, 0x61, 0x08, 0x69, 0xC3, 0x12, 0xA2, 0xEB, 0x50,
0x13, 0x93, 0x22, 0xE2, 0xC4, 0x10, 0xCA, 0x5F, 0xB2, 0x0B,
0xA2, 0x30, 0xC8, 0x54, 0x91, 0x3A, 0x37, 0xFD, 0xD2, 0x10,
0xAB, 0x5A, 0xF8, 0x38, 0xF3, 0xD3, 0xD5, 0x85, 0x58, 0xDE,
0xDF, 0xC0, 0xF4, 0x17, 0x4E, 0xF7, 0x31, 0x79, 0xDD, 0x41,
0x2F, 0xB3, 0x20, 0xC7, 0xEC, 0x98, 0x5E, 0xAE, 0xF7, 0xA9,
0xCB, 0x27, 0x13, 0x72, 0xFE, 0xCA, 0x64, 0xFF, 0x43, 0x93,
0x80, 0x3E, 0x1E, 0xE5, 0x99, 0xBF, 0x41, 0x4B, 0x9D, 0x85,
0x4E, 0x0F,