查看 main 函数,流程比较简单
OllyDBG 断 0x403540,查看 esi 所指内存,拿到 指令->执行函数 对应表
其实 check 函数就是之前发过的 402450 函数,因为之前脚本还原了代码,现在完全不一样了,但也挺简洁明了,注意其中的 strlen(ipt) == 90
很简单的流程
python 算一下 part1_bn = 15691529100101820131
其实这个题目换成求幂(对数,也叫离散对数),难度会大几倍
接下来就要上数论课了(看雪不支持 mathjax,发截图)
[2]: https://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%AE%9A%E7%90%86_%28%E6%95%B0%E8%AE%BA%29
[3]: https://zh.wikipedia.org/wiki/%E6%A8%A1%E5%8F%8D%E5%85%83%E7%B4%A0
[4]: https://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0
因为 第三部分 因为程序的原因有几个限制
void thread1(LPVOID lpThreadParameter)
{
while ( 1 )
{
tmp[] = {0x8Bu, 0xC0u, 0x8Bu, 0xFFu, 0x8Bu, 0xDBu};
WaitForSingleObject(hMutex, 0xFFFFFFFF);
if ( func1_flag == 1 )
{
flOldProtect = 0;
VirtualProtect(&loc_401EC0, 0x2Eu, 0x40u, &flOldProtect);
v1 = 1;
do
{
*((_BYTE *)&loc_401EC0 + v1 - 1) ^= byte_4064F0[v1 - 1];
*((_BYTE *)&loc_401EC0 + v1) ^= byte_4064F0[v1];
v1 += 2;
}
while ( v1 - 1 < 46 );
// 将 401EC0 开始的 0x2E 个字节逐字节与 4064F0 开始的数组异或
VirtualProtect(&loc_401EC0, 0x2Eu, flOldProtect, &flOldProtect);
VirtualProtect(dword_4068E4, 6u, 0x40u, &flOldProtect);
v2 = 0;
v3 = (_BYTE *)dword_4068E4 - tmp;
do
{
v4 = tmp[v2];
v5 = &tmp[v2];
v6 = *(&tmp[v2++] + v3);
v5[v3] = v4;
*v5 = v6;
}
while ( v2 < 6 );
// 直接将 tmp 数组写入 4068E4 指针所指向的地址
VirtualProtect(dword_4068E4, 6u, flOldProtect, &flOldProtect);
func1_flag = 0;
}
ReleaseMutex(hMutex);
Sleep(50u);
}
}
图1
void thread1(LPVOID lpThreadParameter)
{
while ( 1 )
{
tmp[] = {0x8Bu, 0xC0u, 0x8Bu, 0xFFu, 0x8Bu, 0xDBu};
WaitForSingleObject(hMutex, 0xFFFFFFFF);
if ( func1_flag == 1 )
{
flOldProtect = 0;
VirtualProtect(&loc_401EC0, 0x2Eu, 0x40u, &flOldProtect);
v1 = 1;
do
{
*((_BYTE *)&loc_401EC0 + v1 - 1) ^= byte_4064F0[v1 - 1];
*((_BYTE *)&loc_401EC0 + v1) ^= byte_4064F0[v1];
v1 += 2;
}
while ( v1 - 1 < 46 );
// 将 401EC0 开始的 0x2E 个字节逐字节与 4064F0 开始的数组异或
VirtualProtect(&loc_401EC0, 0x2Eu, flOldProtect, &flOldProtect);
VirtualProtect(dword_4068E4, 6u, 0x40u, &flOldProtect);
v2 = 0;
v3 = (_BYTE *)dword_4068E4 - tmp;
do
{
v4 = tmp[v2];
v5 = &tmp[v2];
v6 = *(&tmp[v2++] + v3);
v5[v3] = v4;
*v5 = v6;
}
while ( v2 < 6 );
// 直接将 tmp 数组写入 4068E4 指针所指向的地址
VirtualProtect(dword_4068E4, 6u, flOldProtect, &flOldProtect);
func1_flag = 0;
}
ReleaseMutex(hMutex);
Sleep(50u);
}
}
int sub_402450(const char *a1)
{
dword_4068E4 = &loc_4025DC;
dword_4068E0 = &loc_40263C;
dword_4068EC = &loc_40269C;
if ( (unsigned __int8)((int (*)(void))sub_4027F0)() )
{
v8 = strlen(a1);
if ( v8 <= 256 )
{
v2 = 0;
memset(&Dst, 0, 0xFFu);
v9 = sub_401D50(&v2);
if ( strlen(&v2) == 90 && v4 == 45 && v5 == 45 && v6 == 45 && v7 == 45 )
{
if ( !(unsigned __int8)sub_4027F0(90) )
ExitProcess(1u);
dword_99B6EC = 1;
while ( dword_99B6EC )
;
}
}
}
return 0;
}
import idaapi
tmp_point = {0x4068E4:0x4025DC, 0x4068E0:0x40263C, 0x4068EC:0x40269C}
def dec_func(func_addr, key_addr, tmp_addr, tmp):
func = bytearray(idaapi.get_many_bytes(func_addr, 0x2E))
key = bytearray(idaapi.get_many_bytes(key_addr, 0x2E))
for i in xrange(len(func)):
func[i] ^= key[i]
idaapi.patch_many_bytes(func_addr, str(func))
idaapi.patch_many_bytes(tmp_point[tmp_addr], str(bytearray(tmp)))
dec_func(0x401EC0, 0x4064F0, 0x4068E4, [0x8B, 0xC0, 0x8B, 0xFF, 0x8B, 0xDB])
dec_func(0x402090, 0x406520, 0x4068E0, [0x8B, 0xC0, 0x8B, 0xDB, 0x8B, 0xFF])
dec_func(0x4021D0, 0x406550, 0x4068EC, [0x8B, 0xFF, 0x8B, 0xC0, 0x8B, 0xDB])
# 代码段
text = [0xAA, 0x15, 0x20, 0x01, 0x00, 0x00, 0xAA, 0x15, 0x40, 0x01, 0x00, 0x00, 0xA0, 0x10, 0x00, 0x00,
0x00, 0x00, 0xA8, 0xA0, 0x10, 0xF0, 0x00, 0x00, 0x00, 0xA8, 0xA0, 0x10, 0x60, 0x01, 0x00, 0x00,
0xA7, 0xAA, 0x11, 0x80, 0x00, 0x00, 0x00, 0xAA, 0x10, 0x60, 0x00, 0x00, 0x00, 0xAA, 0x12, 0xB0,
0x00, 0x00, 0x00, 0xA9, 0xA2, 0xEA, 0xA6, 0x0E, 0xA0, 0x10, 0x20, 0x01, 0x00, 0x00, 0xA0, 0x11,
0x10, 0x01, 0x00, 0x00, 0xA4, 0xA5, 0xA0, 0x10, 0x40, 0x01, 0x00, 0x00, 0xA0, 0x11, 0x10, 0x01,
0x00, 0x00, 0xA4, 0xA5]
# 数据段
data = [0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0xBF, 0xB4, 0xD1, 0xA9, 0x43, 0x54, 0x46, 0x32,
0x30, 0x31, 0x37, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x0A, 0x0A, 0x00, 0x00,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
0x77, 0x78, 0x79, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x5A, 0x54, 0x52, 0x50, 0x52, 0x54, 0x5A, 0x58, 0x5A, 0x52, 0x54, 0x5A, 0x58, 0x5A, 0x44,
0x42, 0x40, 0x42, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x57, 0x57, 0x5D, 0x52, 0x5E, 0x57, 0x5E, 0x5C, 0x58, 0x5B, 0x5F, 0x5B, 0x5C, 0x5A, 0x48,
0x45, 0x4A, 0x47, 0x40, 0x47, 0x42, 0x40, 0x4D, 0x48, 0x4D, 0x51, 0x57, 0x52, 0x54, 0x57, 0x51,
0x5F, 0x59, 0x51, 0x52, 0x5F, 0x5F, 0x55, 0x58, 0x5E, 0x41, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x55, 0x56, 0x57, 0x54, 0x54, 0x53, 0x5E, 0x51, 0x5A, 0x52, 0x5B, 0x58, 0x5D, 0x5E, 0x42,
0x45, 0x44, 0x4B, 0x44, 0x4C, 0x41, 0x42, 0x4B, 0x48, 0x48, 0x55, 0x54, 0x5B, 0x54, 0x5C, 0x51,
0x52, 0x5B, 0x58, 0x58, 0x5F, 0x5A, 0x55, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x70, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65,
0x20, 0x6B, 0x65, 0x79, 0x3A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xBF, 0xB4, 0xD1, 0xA9, 0x43, 0x54, 0x46, 0x32, 0x30, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x0D, 0x16, 0x44, 0x02, 0x09, 0x13, 0x48, 0x1D, 0x02, 0x0E, 0x4C, 0x1F, 0x07, 0x08, 0x18,
0x05, 0x52, 0x18, 0x11, 0x0C, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x0D, 0x16, 0x16, 0x45, 0x0D, 0x02, 0x11, 0x49, 0x03, 0x18, 0x4C, 0x03, 0x01, 0x1B, 0x50,
0x03, 0x1B, 0x14, 0x1C, 0x01, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x0D, 0x16, 0x44, 0x02, 0x09, 0x13, 0x48, 0x1D, 0x02, 0x0E, 0x4C, 0x1F, 0x07, 0x08, 0x18,
0x05, 0x52, 0x18, 0x11, 0x0C, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x0D, 0x16, 0x16, 0x45, 0x0D, 0x02, 0x11, 0x49, 0x03, 0x18, 0x4C, 0x03, 0x01, 0x1B, 0x50,
0x03, 0x1B, 0x14, 0x1C, 0x01, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xBF, 0xB4, 0xD1, 0xA9, 0x43, 0x54, 0x46, 0x32, 0x30, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00]
# 填充数据段到 0x1000 长度
for _ in xrange(0x1000 - len(data)):
data.append(0)
def toUint(arr):
return arr[0] | (arr[1]<<8) | (arr[2]<<16) | (arr[3]<<24)
class Context:
def __init__(self):
self.ip = 0
def cmdA0(self):
c = text[self.ip + 1]
p = toUint(text[self.ip+2: self.ip+6])
self.ip += 6
if 0x10 <= c <= 0x13:
# 寄存器间 mov
print "mov r{0}, {1}".format(c - 0x10, hex(p))
elif c == 0x14:
# 这2个是 寄存器和内存间 mov,1字节
print "movb r0, [{0}]".format(hex(p))
elif c == 0x15:
print "movb [{0}], r0".format(hex(p))
else:
assert False
def cmdA1(self):
self.ip += 1
# 异或结果存 r0
print "xor r0, r1"
def cmdA2(self):
p = text[self.ip + 1]
self.ip += 2
# 1字节比较 r0 和 内存,存下比较状态
print "equb r0, [{0}]".format(hex(p))
def cmdA3(self):
assert False
def cmdA4(self):
self.ip += 1
# 弹出对话框
print "msg [r0], [r1]"
def cmdA5(self):
self.ip += 1
# 退出
print "exit"
def cmdA6(self):
p = text[self.ip + 1]
self.ip += 2
# 比较状态为假则跳转相对地址
print "jne +{0}".format(hex(p))
def cmdA7(self):
self.ip += 1
# 输入到内存
print "in [r0]"
def cmdA8(self):
self.ip += 1
# 输出内存到屏幕
print "out [r0]"
def cmdA9(self):
# 调用内置校验函数,返回值存 r0
print "check [r0]"
self.ip += 1
def cmdAA(self):
c = text[self.ip + 1]
p = toUint(text[self.ip+2: self.ip+6])
self.ip += 6
if 0x10 <= c <= 0x12:
# 将后2个内存进行按字节异或存第一个全局变量
print "xorstr key{0}, [{1}], [32]".format(c - 0x10, hex(p))
else:
# 进行按字节异或存第一个内存
print "xorstr [{0}], [32]".format(hex(p))
def run(self):
ops = [self.cmdA0, self.cmdA1, self.cmdA2, self.cmdA3, self.cmdA4, self.cmdA5,
self.cmdA6, self.cmdA7, self.cmdA8, self.cmdA9, self.cmdAA]
while self.ip < len(text):
c = text[self.ip]
ops[c - 0xA0]()
ctx = Context()
ctx.run()
print "-----------------"
def xorstr(name, addr, xoraddr):
txt = ""
i = 0
while True:
t = data[addr + i]
if t == 0:
break
txt += chr(t ^ data[32 + i])
i += 1
print name, txt
xorstr("key0:", 0x60, 32)
xorstr("key1:", 0x80, 32)
xorstr("key2:", 0xB0, 32)
xorstr("ok:", 0x120, 32)
xorstr("fail:", 0x140, 32)
print "[0xea] = ", hex(data[0xea])
xorstr [0x120], [32] ; you got the right key!
xorstr [0x140], [32] ; your key is not right!
mov r0, 0x0
out [r0]
mov r0, 0xf0
out [r0]
mov r0, 0x160
in [r0] ; 获取用户输入,存数据地址0x160,寄存器 r0 指向它
xorstr key1, [0x80], [32] ; 1549780652036258484424751705102781884386113
xorstr key0, [0x60], [32] ; 98765432109876543210123
xorstr key2, [0xb0], [32] ; 9753124680975312468097531246809753124680
check [r0] ; 调用检验函数
equb r0, [0xea] ; [0xea] = 1,意思是上面的函数返回真
jne +0xe ; 假就跳到失败框
mov r0, 0x120
mov r1, 0x110
msg [r0], [r1] ; 成功信息框
exit
mov r0, 0x140
mov r1, 0x110
msg [r0], [r1] ; 失败信息框
exit
int __cdecl check(const char *src)
{
if ( crc_check() // 检测函数是否被修改,也包含是否被软断点
&& (srclen = strlen(src), srclen <= 256)
&& (ipt[0] = 0, memset(&ipt[1], 0, 255u),
v4 = base64_decode(src, srclen, ipt), strlen(ipt) == 90) // 这个strlen(ipt) == 90 要注意
// 代表整个 ipt 中不能有 00
&& ipt[20] == '-' // 序列号分隔符
&& ipt[21] == '-'
&& ipt[61] == '-'
&& ipt[62] == '-' )
{
if ( !crc_check() )
ExitProcess(1u);
thread_flag = 1;
while ( thread_flag )
;
if ( check_part1(ipt) ) // 检验第一部分 ipt[:20]
{
thread_flag = 1;
while ( thread_flag )
;
if ( !crc_check() )
ExitProcess(1u);
thread_flag = 2;
while ( thread_flag )
;
if ( check_part2(ipt) ) // 检验第二部分 ipt[22:61]
{
thread_flag = 2;
while ( thread_flag )
;
if ( !crc_check() )
ExitProcess(1u);
thread_flag = 3;
while ( thread_flag )
;
if ( check_part3(ipt) ) // 检验第三部分 ipt[63:90]
{
thread_flag = 3;
while ( thread_flag )
;
if ( !crc_check() )
ExitProcess(1u);
result = 1;
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
{
result = 0;
}
}
else
{
result = 0;
}
return result;
}
signed int check_part1(_BYTE *a1)
{
__asm { fcmovnbe st, st(2) }
v1 = __rdtsc();
v10 = (unsigned int)v1 + ((unsigned __int64)HIDWORD(v1) << 32);
v2 = a1;
v3 = &part1_bn[1] - a1;
v9 = 4;
while ( 1 )
{
v4 = *v2 ^ v2["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - a1];
v2 += 5;
v2[part1_bn - a1 - 5] = v4;
v2[v3 - 5] = *(v2 - 4) ^ v2[0x405145 - (_DWORD)a1 - 5];
v2[&part1_bn[2] - a1 - 5] = *(v2 - 3) ^ v2[0x405146 - (_DWORD)a1 - 5];
v2[&part1_bn[3] - a1 - 5] = *(v2 - 2) ^ v2[0x405147 - (_DWORD)a1 - 5];
v5 = v9-- == 1;
v2[&part1_bn[4] - a1 - 5] = *(v2 - 1) ^ v2[0x405148 - (_DWORD)a1 - 5];
if ( v5 )
break;
v3 = &part1_bn[1] - a1;
} // 拿ipt[:20] 与 abcdef...z 进行按字节异或存 part1_bn
v6 = big_mul(part1_bn, key0); // key0 = 98765432109876543210123
v8 = __rdtsc(); // key1 = 1549780652036258484424751705102781884386113
if ( !strcmp(v6, key1) && (unsigned int)v8 + ((unsigned __int64)HIDWORD(v8) << 32) - v10 < 8888888 )
{
operator delete(v6);
result = 1;
}
else
{
operator delete(v6);
result = 0;
}
return result;
}
signed int check_part2(_BYTE *a1)
{
__asm { fcmovnbe st, st(2) }
v1 = __rdtsc();
v2 = ((unsigned __int64)HIDWORD(v1) << 32) + (unsigned int)v1;
v3 = 0;
do
{
v4 = aAbcdefghijklmn[v3] ^ a1[v3 + 22]; // abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
v3 += 3;
byte_99B705[v3] = v4;
byte_99B706[v3] = *(_BYTE *)(v3 + 0x405142) ^ a1[v3 + 20];
byte_99B707[v3] = *(_BYTE *)(v3 + 0x405143) ^ a1[v3 + 21];
}
while ( v3 < 39 );
v5 = big_mul(part2_bn, part2_bn);
big_mul_fft(v5, key2); // 这里是个误导,其实没有用他的结果
if ( strcmp(v5, a13095069099216) ) // 13095069099216326605010245808779535277211541324456558063162414338128147458401
{
operator delete(v5);
return 0;
}
operator delete(v5);
v7 = __rdtsc();
if ( (unsigned int)v7 + ((unsigned __int64)HIDWORD(v7) << 32) - v2 >= 0x14B230CE38i64 )
return 0;
return 1;
}
int check_part3(_BYTE *a1)
{
v1 = __rdtsc();
v23 = (unsigned int)v1 + ((unsigned __int64)HIDWORD(v1) << 32);
bi_new(bi1);
dst[0] = 0;
memset(&dst[1], 0, 55u);
v2 = a1 + 63;
v3 = &dst[1];
v4 = 27;
do
{
v5 = *v2;
*(v3 - 1) = *v2 / 16;
*v3 = v5 % 16;
++v2;
v3 += 2;
--v4;
}
while ( v4 );
v6 = 0;
do
{
v7 = dst[v6];
if ( v7 < 0 || v7 > 9 )
v8 = v7 + 0x37;
else
v8 = v7 + '0';
dst[v6] = v8;
v9 = dst[v6 + 1];
if ( v9 < 0 || v9 > 9 )
v10 = v9 + 0x37;
else
v10 = v9 + '0';
dst[v6 + 1] = v10;
v11 = dst[v6 + 2];
if ( v11 < 0 || v11 > 9 )
v12 = v11 + 0x37;
else
v12 = v11 + 48;
dst[v6 + 2] = v12;
v13 = dst[v6 + 3];
if ( v13 < 0 || v13 > 9 )
v14 = v13 + 55;
else
v14 = v13 + 48;
dst[v6 + 3] = v14;
v15 = dst[v6 + 4];
if ( v15 < 0 || v15 > 9 )
v16 = v15 + 0x37;
else
v16 = v15 + 48;
dst[v6 + 4] = v16;
v17 = dst[v6 + 5];
if ( v17 < 0 || v17 > 9 )
v18 = v17 + 55;
else
v18 = v17 + '0';
dst[v6 + 5] = v18;
v6 += 6;
}
while ( v6 < 54 ); // dst = 输入的 hex 编码
bi_set(bi1, dst, 16);
bi2_p = bi_new(bi2);
bi_set(bi2_p, part1_bn, 10); // part1_bn = 15691529100101820131
bi3_p = bi_new(bi3);
bi_set(bi3_p, part2_bn, 10); // part2_bn = 114433688655117320765854989491151409201
powmod(bi1, bi2, (int)&a2, bi3);
result = 0;
if ( v25 == 4 )
{
while ( v26[result] == byte_4064E0[result] )// 71639176673360967005214790689576394595
{
++result;
if ( result >= 4 )
{
v22 = __rdtsc();
if ( (unsigned int)v22 + ((unsigned __int64)HIDWORD(v22) << 32) - v23 < 88888888 )
return 1;
break;
}
}
result = 0;
}
return result * 4;
}
import gmpy2
import base64
key0 = 98765432109876543210123
key1 = 1549780652036258484424751705102781884386113
key2 = 13095069099216326605010245808779535277211541324456558063162414338128147458401
key3 = long("35e5341c28494bcc881e49a704971f63", 16) #71639176673360967005214790689576394595
xordt = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
part1_bi = 0
part2_bi = 0
def decode_part1():
global part1_bi
part1_bi = key1 / key0
partstr = bytearray(str(part1_bi))
for i in xrange(len(partstr)):
partstr[i] ^= ord(xordt[i])
return partstr
def decode_part2():
global part2_bi
part2_bi = long(gmpy2.isqrt(key2))
partstr = bytearray(str(part2_bi))
for i in xrange(len(partstr)):
partstr[i] ^= ord(xordt[i])
return partstr
# 先求出两部分大数
decode_part1()
decode_part2()
g = 55986991232018409201158808992848352475
m = part2_bi #"2a1eb3c9579dfa307cf5b6c8730114db"
k = long("0x"+"6"*54, 16) / m
g = g + (k-1) * m #找个能填充满 27字节,前面都是 66的最近的g
def checkok(s):
ttt = hex(s)[2:].rstrip("L").decode("hex")
assert len(ttt) == 27
for xxx in ttt:
# 不是0,并且小于 0x80
if (ord(xxx) == 0) or ((ord(xxx) & 0x80) != 0):
return False
return True
while True:
if checkok(g):
break
# 向前寻找
g -= m
fake = decode_part1() + "--" + decode_part2() + "--" + hex(g)[2:].rstrip("L").decode("hex")
assert len(fake) == 90
print base64.b64encode(fake)
- 准备 虚拟机代码段(code)
- 准备 虚拟机数据段(data)
- 准备 虚拟机上下文(ctx)
- 运行虚拟机(0x403540,eax=code, esi=ctx, arg0=data)
- 先将 ipt[:20] 与 a..z 异或得到 part1_bn
- big_mul 是简易大数乘法,输入是两个大数字符串,输出大数字符串
- 检测
part1_bn * 98765432109876543210123 == 1549780652036258484424751705102781884386113
- 拖入 IDA,发现有3个 TLS 回调,其中有1个回调启动了6个线程,但只有3个线程是解密函数,都类似如下代码
- 由于 4068E4 存的是指针,查找引用找到一个函数(现在还不知道是啥),但是能看到这个指针指向了这个函数段里的内
int sub_402450(const char *a1)
{
dword_4068E4 = &loc_4025DC;
dword_4068E0 = &loc_40263C;
dword_4068EC = &loc_40269C;
if ( (unsigned __int8)((int (*)(void))sub_4027F0)() )
{
v8 = strlen(a1);
if ( v8 <= 256 )
{
v2 = 0;
memset(&Dst, 0, 0xFFu);
v9 = sub_401D50(&v2);
if ( strlen(&v2) == 90 && v4 == 45 && v5 == 45 && v6 == 45 && v7 == 45 )
{
if ( !(unsigned __int8)sub_4027F0(90) )
ExitProcess(1u);
dword_99B6EC = 1;
while ( dword_99B6EC )
;
}
}
}
return 0;
}
- 为了让大家看到代码地址,特意将命名去除了,其他两个线程和这个差不多,只是解密的函数地址不一样,写个脚本还原代码
import idaapi
tmp_point = {0x4068E4:0x4025DC, 0x4068E0:0x40263C, 0x4068EC:0x40269C}
def dec_func(func_addr, key_addr, tmp_addr, tmp):
func = bytearray(idaapi.get_many_bytes(func_addr, 0x2E))
key = bytearray(idaapi.get_many_bytes(key_addr, 0x2E))
for i in xrange(len(func)):
func[i] ^= key[i]
idaapi.patch_many_bytes(func_addr, str(func))
idaapi.patch_many_bytes(tmp_point[tmp_addr], str(bytearray(tmp)))
dec_func(0x401EC0, 0x4064F0, 0x4068E4, [0x8B, 0xC0, 0x8B, 0xFF, 0x8B, 0xDB])
dec_func(0x402090, 0x406520, 0x4068E0, [0x8B, 0xC0, 0x8B, 0xDB, 0x8B, 0xFF])
dec_func(0x4021D0, 0x406550, 0x4068EC, [0x8B, 0xFF, 0x8B, 0xC0, 0x8B, 0xDB])
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)