1. TlsCallback
创建了6个线程, 前3个线程是负责smc解码的, 后3个线程没用
.text:00402D30 TlsCallback_2
线程1: 解码004025DC处的跳转及check1函数
.text:00402830 thread1
.text:004025DC push offset loc_4025E2
.text:004025E1 retn
.text:004025E2 lea ecx, [ebp+var_110]
.text:004025E8 push ecx
.text:004025E9 call check1
线程2: 解码0040263C处的跳转及check2函数
.text:00402970 thread2
.text:0040263C push offset loc_402642
.text:00402641 retn
.text:00402642 lea eax, [ebp+var_110]
.text:00402648 push eax
.text:00402649 call check2
线程3: 解码0040269C处的跳转及check3函数
.text:00402A90 thread3
.text:0040269C push offset loc_4026A2
.text:004026A1 retn
.text:004026A2 lea edx, [ebp+var_110]
.text:004026A8 push edx
.text:004026A9 call check3
2. 主流程
一个自定义的虚拟机
校验函数
.text:00402700 fn_check
检测代码改动
.text:00402481 call check_text_areas
sn=base64_decode(sn)
.text:0040251D call base64_decode
sn的格式(共90位): (20位)--(39位)--(27位)
.text:00402573 cmp [ebp+var_130], 90
.text:0040257A jnz short loc_4025AC
.text:0040257C movsx edx, [ebp+Dst+14h]
.text:00402583 cmp edx, '-'
.text:00402586 jnz short loc_4025AC
.text:00402588 movsx eax, [ebp+Dst+15h]
.text:0040258F cmp eax, '-'
.text:00402592 jnz short loc_4025AC
.text:00402594 movsx ecx, [ebp+Dst+3Dh]
.text:0040259B cmp ecx, '-'
.text:0040259E jnz short loc_4025AC
.text:004025A0 movsx edx, [ebp+Dst+3Eh]
.text:004025A7 cmp edx, '-'
.text:004025AA jz short loc_4025B2
校验前20位
(sn1 xor abcdefg...) * 98765432109876543210123 == 1549780652036258484424751705102781884386113
.text:004025E9 call check1
校验中间39位
(sn2 xor abcdefg...) ^ 2 == 13095069099216326605010245808779535277211541324456558063162414338128147458401
.text:00402649 call check2
检验后27位, sn3视为16进制
sn3 ^ 15691529100101820131 mod 114433688655117320765854989491151409201 == 71639176673360967005214790689576394595
.text:004026A9 call check3
sn3作为16进制转换的时候是有符号转换的, 所以导致>=80的值无法正常转换
这里只需要关心能产生0x00的值即可(有挺多个, 如0x89)
for (int i = 8; i < 16; i++)
{
for (int k = 0; k < 16; k++)
{
int v = (char)((i << 4) | k);
char v1 = v / 16;
char v2 = v % 16;
v1 += v1 < 0 ? 0x37 : 0x30;
v2 += v2 < 0 ? 0x37 : 0x30;
// 这里非数字字母的字符, 后面都会被0替代
printf("%02X: %c%c\n", (BYTE)v, v1, v2);
}
}
3. 后27位计算
已知:
e = 15691529100101820131
n = 114433688655117320765854989491151409201
m = 71639176673360967005214790689576394595
分解得到
d = 98395538376216701876091105738065053007
c = m ^ d mod n = 55986991232018409201158808992848352475 (2A1EB3C9579DFA307CF5B6C8730114DB)
c中>=0x80的是无法通过转换得到的(如B3, C9, ...)
sn3(27字节) > c (16字节)
c ^ e mod n = m, 根据(a * b) mod n = (a mod n) * (b mod n) mod n
得 (c mod n) * (c mod n) * ... mod n = m
再由c mod n = (c + k * n) mod n, 代入上式得到
(c + k * n) ^ e mod n = m
根据下面这两个条件可以立刻得到很多解(如: 0208674855670d0560353c3a1d3e242e217766)
sn3 = c + k * n
sn3中的字节必须小于0x80
得到的解, 在前面填充可以转换成00的值: 89898989898989890208674855670d0560353c3a1d3e242e217766
与前面的串连接起来base64得到最终结果
UFdVXVRTVVFYWltdXV9XQkFDQEUtLVBTV1BWVVFQUVxeWVxfWENDQkRCQE5CTEBCWFZaVVRTVlxZU1lcXC0tiYmJiYmJiYkCCGdIVWcNBWA1PDodPiQuIXdm
4. 穷举脚本
import itertools
n=114433688655117320765854989491151409201
e=15691529100101820131
c=55986991232018409201158808992848352475
def valid_result(v):
sv=hex(v)[2:]
sv_len=len(sv)
if (sv_len&1) != 0:
sv='0'+sv
sv_len=sv_len+1
for i in itertools.count(0,2):
if (i>=sv_len):
break
if (ord(sv[i])>=0x38):
return False
return True
def solve(ibegin,iend):
g=0
nc=c
k=0
for i in itertools.count(0):
g=g+1
nc=nc+n
if ((ibegin+i)>=iend):
break;
#print(nc)
#print(pow(nc,e,n))
if (g>=1000000):
print(ibegin+i)
g=0
if (valid_result(nc)):
print('---')
print(i)
print(nc)
print(hex(nc))
#break
return
solve(0,4294967296)
'''
---
396154
45333533916159234226406484520676079360374630
0x208674855670d0560353c3a1d3e242e217766
---
456935
52288927946305920099875916636937753163020611
0x2583f59392b7266031a47246a1e672b013943
...
'''
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课