2024 强网杯逆向 Writeups - gaoyucan - 博客园
[推荐][原创] 强网杯2024 ez_vm 手撕VM + DFA Attack Whitebox AES-CTF对抗-看雪-安全社区|安全招聘|kanxue.com
太难了,被暴打了
Mips
出题人应该不会好心的给你一个qemu-static,应该是经过魔改的
发现有一个smc
qemu-mips -g 12345 ./mips_bin #QEMU在12345端口上开启一个GDB服务器,这样GDB可以远程连接并控制QEMU的执行。
#gdb的调试方法
#另外开一个窗口
gdb-multiarch ./mips_bin
set arch mips
set endian big
target remote localhost:12345 #GDB连接到本地的12345端口
#ida的调试方法
ida remote gdbserver
这道题目的几个好玩的地方
-
首先是mmap这个函数,在0x23000地址映射了一片区域,方便了魔改的qemu做手脚
-
这里又开了个子线程,调试的方法,先下个断点,然后再开个ida附加,或者直接set ip直接过掉
-
直接emu -g 无法开启gdbserver,直接patch一下就可以了
-
可以先编译一个qemu-user-linux 然后bindiff恢复大部分符号方便逆向分析
-
这里opcodes是个smc,直接动态调试,创建函数
发现只是一个简单的异或
cipher="sxrujtv`labiVzbp`vpg|" for i in range(21): print(chr(ord(cipher[i])^(0x15-i)),end="")
得到了一个假flag flag{dynamic_reverse}
显然中间有暗改的地方
动态跟踪一直到最后都没有看到数据暗改的地方,那么只有write函数做了手脚
这里可以猜到qemu对syscall的调用进行了暗改,我们要先找到qemu-write的系统调用
通过函数特征可以定位到这里
这样就找到了flag效验的地方,找到加密函数
加密流程分析
1.进入encrypt函数,实际上是 input-> 移位加密 -> xor_keystream -> 标准RC4加密
j=0
for i in range(22):
j+=sbox[i]
sbox[i],sbox[j&0xff]=sbox[j&0xff],sbox[i]
k=((rol(input[i+5],7)<<6)^0xC0| (rol(input[i+5],7) >>2)^0x3B)^0xBE
h=((rol(k,5)^0x3D) <<4 | (rol(k,5)^0xAD) >>4)^ 0xDE
key2=[0xDE, 0xAD, 0xBE, 0xEF]
cipher[i]=sbox[(sbox[j]+sbox[i])&0xff]^key2[i%4]^rol(h,3)
2.encrypt函数外部 xor_keystream
3.swap(7,11) swap(12,16) ->cipher
直接对着写解密脚本
from string import printable
cipher = [
0x000000C4, 0x000000EE, 0x0000003C, 0x000000BB, 0x000000E7, 0x000000FD, 0x00000067, 0x0000001D,
0x000000F8, 0x00000097, 0x00000068, 0x0000009D, 0x0000000B, 0x0000007F, 0x000000C7, 0x00000080,
0x000000DF, 0x000000F9, 0x0000004B, 0x000000A0, 0x00000046, 0x00000091, 0x00000000, 0x00000000
]
def swap(a,l,r):
a[l],a[r] = a[r],a[l]
def rol(x,n):
return ((x<<n)|(x>>(8-n)))&0xff
#生成RC4密钥流
j=0
key="6105t3"
sbox=[i for i in range(256)]
keybox=[0]*256
k=[ord(key[i%6]) for i in range(256)]
for i in range(256):
a=sbox[i]
b=k[i]
j+=(a+b)
sbox[i],sbox[j&0xff]=sbox[j&0xff],sbox[i]
j=0
i=0
for _ in range(256):
i = (i + 1) % 256
j= (j+sbox[i])%256
sbox[i],sbox[j&0xff]=sbox[j&0xff],sbox[i]
keybox[_]=sbox[(sbox[j&0xff]+sbox[i])&0xff]
#print(keybox)
""" 加密流程分析
1.进入encrypt函数,实际上是 input-> 移位加密 -> xor_keystream -> 标准RC4加密
j=0
for i in range(22):
j+=sbox[i]
sbox[i],sbox[j&0xff]=sbox[j&0xff],sbox[i]
k=((rol(input[i+5],7)<<6)^0xC0| (rol(input[i+5],7) >>2)^0x3B)^0xBE
h=((rol(k,5)^0x3D) <<4 | (rol(k,5)^0xAD) >>4)^ 0xDE
key2=[0xDE, 0xAD, 0xBE, 0xEF]
cipher[i]=sbox[(sbox[j]+sbox[i])&0xff]^key2[i%4]^rol(h,3)
2.encrypt函数外部 xor_keystream
3.swap(7,11) swap(12,16) ->cipher
"""
#解密流程
swap(cipher,12,16)
swap(cipher,7,11)
for i in range(len(cipher)):
cipher[i] ^=0xa
for i in range(len(cipher)):
cipher[i]^=keybox[i]
key2=[0xDE, 0xAD, 0xBE, 0xEF]
for i in range(len(cipher)):
cipher[i]^=key2[i%4]
#移位加密 直接爆破吧
flag=""
for i in range(len(cipher)):
for ch in printable:
k=((rol(ord(ch),7)<<6)^0xC0| (rol(ord(ch),7) >>2)^0x3B)^0xBE
k&=0xff
h=((rol(k,5)^0x3D) <<4 | (rol(k,5)^0xAD) >>4)^ 0xDE
h&=0xff
if rol(h,3)==cipher[i]:
print(ch,end="")
break
斯内克
Hint: 赛题附件已更新,总体算法并未修改。对于解决此赛题,需关注以下内容:
- 需要选手的操作序列最短
- 赛题内设用于触发验证的轮次减少
- 选手可忽略由蛇的身体长度引起的可能
蛇要最优走好每一步;蛇不应该直接调头(如当蛇往右走时,不能直接转变方向为左),否则会咬伤自己。
首先总结一下游戏流程
移动贪吃蛇,每一步会解密一段shellcode,如果吃到食物,并且shellcode的md5等于预设的值就执行这段shellcode,即真正的flagcheck逻辑
opcodes太长了,直接dump出来然后再解密
import idc
start=0x7FF77CF9F000
end=0x7FF77CF9F47F
with open("dump.bin","wb") as f:
for addr in range(start,end+1):
val=idc.get_bytes(addr,1)
f.write(val)
直接根据题目逻辑写贪心
from ctypes import *
from hashlib import *
cdll.msvcrt.srand(0XDEADBEEF)
food_pos=[]
for i in range(20):
food_pos.append((cdll.msvcrt.rand()%20,cdll.msvcrt.rand()%20))
print(food_pos)
snake_pos=(10,10)
with open(r'C:\Users\Npc\Desktop\CTF\Events\2024qwb\SNAKEEE\dump.bin',"rb") as f:
opcode=f.read()
opcodes=[i for i in opcode]
""" code的解密观察
if ( Buffer.Event.KeyEvent.wVirtualKeyCode == 37 )// <-
{
++step_count;
prev_keycode = 37;
steps = 3;
for ( j = 0; j < 1152; ++j )
opcodes[j] = ((int)(unsigned __int8)opcodes[j] >> 5) | (8 * opcodes[j]);
}
else
{
switch ( wVirtualKeyCode )
{
case 38: // ↑
++step_count;
steps = 0;
prev_keycode = 38;
j_memcpy(v7, opcodes, 0x480uLL);
for ( k = 0; k < 1152; ++k )
opcodes[k] = v7[(k + 6) % 1152];
break;
case 39: // ->
++step_count;
prev_keycode = 39;
steps = 2;
for ( m = 0; m < 1152; ++m )
opcodes[m] -= 0x66;
break;
case 40: // ↓
++step_count;
prev_keycode = 40;
steps = 1;
for ( n = 0; n < 1152; ++n )
opcodes[n] += 0x1E;
break;
"""
'''steps:
0 x-- a
1 x++ d
2 y-- w
3 y++ s
'''
move=1 #初始向右
snake_x,snake_y=snake_pos
for food_x,food_y in food_pos:
dx=food_x-snake_x
dy=food_y-snake_y
#snake吃到食物
snake_x,snake_y=food_x,food_y
while True:
last=move
#!如果上次移动方向与这次将要移动的方向相同,就延续上一步操作,避免转弯
if last==0 and dx<0:
dx=0
move=0
if last==1 and dx>0:
dx=0
move=1
if last==2 and dy<0:
dy=0
move=2
if last==3 and dy>0:
dy=0
move=3
#根据食物的位置,确定下一步的移动方向
if dx>0 and last!=0:
dx=0
move=1
elif dx<0 and last!=1:
dx=0
move=0
elif dx==0 and last==2 and dy>0: #特殊情况的处理
dx=1
move=1
elif dx==0 and last==3 and dy<0:
dx=1
move=1
else:
if dy>0 and last!=2:
dy=0
move=3
elif dy<0 and last!=3:
dy=0
move=2
elif dy==0 and last==1 and dx<0:
dy=1
move=2
elif dy==0 and last==0 and dx>0:
dy=1
move=3
if last != move:
# print(f"w,dx={dx},dy={dy}")
match move:
case 0:
print(f"a,dx={dx},dy={dy}")
opcodes = opcodes[6:] + opcodes[:6]
case 1:
print(f"d,dx={dx},dy={dy}")
for k in range(len(opcodes)):
opcodes[k] = (opcodes[k] + 0x1E) & 0xFF
case 2:
print(f"w,dx={dx},dy={dy}")
for k in range(len(opcodes)):
opcodes[k] = (opcodes[k] - 0x66) & 0xFF
case 3:
print(f"s,dx={dx},dy={dy}")
for k in range(len(opcodes)):
opcodes[k] = ((opcodes[k] >> 5) | (opcodes[k] << 3)) & 0xFF
if dx==0 and dy==0:
break
tmp_code = b''
for c in opcodes:
tmp_code += c.to_bytes(1)
# print(md5(tmp_code).hexdigest())
if (md5(tmp_code).hexdigest() == "9c06c08f882d7981e91d663364ce5e2e"):
print("Found")
with open("opcodes.bin", "wb") as f:
f.write(tmp_code)
exit()
#wasawdsawdsawds
发现是tea解密
cipher=[0]*16
cipher[0]=0x98
cipher[1]=0xA0
cipher[2]=0xD9
cipher[3]=0x98
cipher[4]=0xBA
cipher[5]=0x97
cipher[6]=0x1B
cipher[7]=0x71
cipher[8]=0x9B
cipher[9]=0x81
cipher[10]=0x44
cipher[11]=0x2F
cipher[12]=0x55
cipher[13]=0xB8
cipher[14]=0x37
cipher[15]=0xDF
cipher=memoryview(bytearray(cipher)).cast('I').tolist()
print(cipher)
key=b"W31c0m3. 2 QWBs8"
key=memoryview(bytearray(key)).cast('I').tolist()
print(key)
cipher[2]^=cipher[1]
cipher[3]^=cipher[0]
cipher[1]^=cipher[3]
cipher[0]^=cipher[2]
delta=0x9E3779B9
sum=(delta*0x40)&0xffffffff
for i in range(0x20):
cipher[3]-=(key[(sum >> 11) & 3] + sum) ^ (cipher[2] + ((cipher[2] >> 5) ^ (16 * cipher[2])))
cipher[3]&=0xffffffff
sum-=delta
sum&=0xffffffff
cipher[2]-=(key[sum & 3] + sum) ^ (cipher[3] + ((cipher[3] >> 5) ^ (16 * cipher[3])))
cipher[2]&=0xffffffff
for i in range(0x20):
cipher[1]-=(key[(sum >> 11) & 3] + sum) ^ (cipher[0] + ((cipher[0] >> 5) ^ (16 * cipher[0])))
cipher[1]&=0xffffffff
sum-=delta
sum&=0xffffffff
cipher[0] -= (key[sum & 3] + sum) ^ (cipher[1] + ((cipher[1] >> 5) ^ (16 * cipher[1])))
cipher[0]&=0xffffffff
for i in cipher:
print((i.to_bytes(4,'little').decode()),end='')
#[2564399256, 1897633722, 793018779, 3744970837]
#[1664168791, 775122224, 1361064480, 947077719]
#flag{G0@d_Snake}
bbox
人肉做反而比写算法要快
先把地图map给提取出来
可以发现,每个关卡的地图大小是400,行20,宽20
import idc
start = 0x0404040
size = 5600*4
output_file_path = 'output.txt' # 指定输出文件路径
# 打开文件以进行写入
with open(output_file_path, 'w') as f:
for i in range(14):
for j in range(20):
for k in range(20):
addr = start + (i * 400 + 20 * j + k)*4
print(hex(addr))
val = idc.get_bytes(addr, 1)
f.write(' '+str(int.from_bytes(val, byteorder='little')))
f.write('\n')
f.write(f'----------------level{i}-------------------------\n')
print(f"数据已成功写入到 {output_file_path}")
最后4关是字符画,只有0-8关推箱子 9-12 qwb!
1是墙壁,0是通路,3是箱子,4是终点
人肉做
2 12 13 9 21 13 31 3
flag{qwb!_fec2d316d20dbacbe0cdff8fb6ff07b9}
remem
IDA 打不开 报错 Bad ELF byte sex 2 for the indicated machine
64位小端的elf头,被错误的修改为32位大端,操作系统能识别这种错误,但是ida识别不了
直接修改正确后,用ida打开
发现是vm,case 里的操作里包含 mmap 和unmap ,应该是个jit,所以只能动调,然后判断干了些啥
直接断在每个case的call rax
动调测试得到的opcodes
case F2 0 : x*x
case F2 3 : x*factor[i] i为调用的次数
case F0 0 3: a=pop()+pop() push(a)
case F1 0 3: a=pop()-pop() push(a)
case F6 3 : stack.push(pop() % 0x5E2F4391) rdx:存储余数 rax:存储商
case F3 : x=x^check_stack.pop()^enc[i] i为调用的次数
case f8 end
直接进行栈的模拟
opcodes=[0x000000F2, 0x00000000, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000000, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000000, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000000, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000000, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F2, 0x00000000, 0x000000F2, 0x00000003, 0x000000F7, 0x000000F0, 0x00000000, 0x00000003, 0x000000F1, 0x00000000, 0x00000003, 0x000000F6, 0x00000003, 0x000000F0, 0x00000000, 0x00000003, 0x000000F1, 0x00000000, 0x00000003, 0x000000F6, 0x00000003, 0x000000F0, 0x00000000, 0x00000003, 0x000000F1, 0x00000000, 0x00000003, 0x000000F6, 0x00000003, 0x000000F0, 0x00000000, 0x00000003, 0x000000F0, 0x00000000, 0x00000003, 0x000000F6, 0x00000003, 0x000000F0, 0x00000000, 0x00000003, 0x000000F0, 0x00000000, 0x00000003, 0x000000F1, 0x00000000, 0x00000003, 0x000000F6, 0x00000003, 0x000000F7, 0x000000F3, 0x00000000, 0x00000003, 0x000000F3, 0x00000000, 0x00000003, 0x000000F3, 0x00000000, 0x00000003, 0x000000F3, 0x00000000, 0x00000003, 0x000000F3, 0x00000000, 0x00000003, 0x000000F8]
opcodes=[hex(i) for i in opcodes]
print(opcodes)
stack=[0]*18
""" stack[0] = (unsigned int)input_0;
stack[1] = (unsigned int)input_0;
stack[2] = (unsigned int)input_1;
stack[3] = (unsigned int)input_1;
stack[4] = (unsigned int)input_0;
stack[5] = (unsigned int)input_1;
stack[6] = (unsigned int)input_0;
stack[7] = (unsigned int)input_0;
stack[8] = (unsigned int)input_2;
stack[9] = (unsigned int)input_2;
stack[10] = (unsigned int)input_3;
stack[11] = (unsigned int)input_2;
stack[12] = (unsigned int)input_3;
stack[13] = (unsigned int)input_3;
stack[14] = (unsigned int)input_4;
stack[15] = (unsigned int)input_4;
stack[16] = 0LL;
stack[17] = 0LL; """
"""
factor[0] = 3;
factor[1] = input_1;
factor[2] = 6;
factor[3] = 82;
factor[4] = 6;
factor[5] = 2;
factor[6] = 13;
factor[7] = 17;
factor[8] = input_2;
factor[9] = 5;
factor[10] = 5;
factor[11] = 88;
factor[12] = input_2;
factor[13] = 4;
factor[14] = 5;
factor[15] = 232;
factor[16] = 35;
factor[17] = 8;
factor[18] = 16"""
check_stack=[0]*100
enc=[0x42DB9F06, 0x35368926, 0x509A3978, 0x1EBFA92F, 0x555CC98C]
enc=[hex(i) for i in enc]
factor=['3','input_1','6','82','6','2','13','17','input_2','5','5','88','input_2','4','5','232','35','8','16']
stack=['input_0','input_0','input_1','input_1','input_0','input_1','input_0','input_0','input_2','input_2','input_3','input_2','input_3','input_3','input_4','input_4',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]+[0]*100
sp=18
csp=0
ip=0
v20=1
v21="input_0"
f2_count=0
f3_count=0
'''动调测试得到的opcodes
case F2 0 : x*x
case F2 3 : x*factor[i] i为调用的次数
case F0 0 3: a=pop()+pop() push(a)
case F1 0 3: a=pop()-pop() push(a)
case F6 3 : stack.push(pop() % 0x5E2F4391) rdx:存储余数 rax:存储商
case F3 : x=x^check_stack.pop()^enc[i] i为调用的次数
case f8 end
'''
while True:
if ip>=len(opcodes):
break
opcode=opcodes[ip]
match opcode:
case '0xf2':
if opcodes[ip+1]=='0x0':
v21="("+v21+"*"+v21+")"
# print(f"{v21}={v21}*{v21}")
elif opcodes[ip+1]=='0x3':
v21="("+v21+"*"+factor[f2_count]+")"
# print(f"{v21}={v21}*{factor[f2_count]}")
f2_count+=1
ip+=2
case '0xf0':
if opcodes[ip+1]=='0x0' and opcodes[ip+2]=='0x3':
sp-=1
a=stack[sp]
sp-=1
b=stack[sp]
stack[sp]=str(a)+"+"+str(b)
sp+=1
ip+=3
case '0xf1':
if opcodes[ip+1]=='0x0' and opcodes[ip+2]=='0x3':
sp-=1
a=stack[sp]
# type(a)
sp-=1
b=stack[sp]
# type(b)
stack[sp]=str(a)+"-"+str(b)
sp+=1
ip+=3
case '0xf6':
if opcodes[ip+1]=='0x3':
sp-=1
a=stack[sp]
#print(csp)
check_stack[csp]="("+a+")"+"%0x5E2F4391"
csp+=1
ip+=2
case '0xf3':
csp-=1
a=check_stack[csp]
v21="("+str(a)+"^"+str(v21)+"^"+enc[f3_count]+")"
f3_count+=1
ip+=3
case '0xf7':
stack[sp]=v21
sp+=1
v14=v20
v21=stack[v14]
v20+=1
ip+=1
case '0xf8':
print(v21)
exit(1)
case _:
print(opcode)
continue
((((input_4*input_4)*16)+(input_4*8)-((input_3*input_3)*35))%0x5E2F4391^(((input_3*232)+((input_2*input_2)*5)-((input_3*input_2)*4))%0x5E2F4391^(((input_2*88)+((input_2*input_2)*5)-((input_0*input_2)*5))%0x5E2F4391^(((input_0*17)+(input_1*13)+((input_0*input_0)*2))%0x5E2F4391^(((input_1*6)+(input_1*82)+((input_0*input_1)*6)-((input_0*input_0)*3))%0x5E2F4391^0^0x42db9f06)^0x35368926)^0x509a3978)^0x1ebfa92f)^0x555cc98c)
把异或视为判断,并将表达式转换成⽅程组。化简结果可以得到
(((input_1*6)+(input_1*82)+((input_0*input_1)*6)-((input_0*input_0)*3))%0x5E2F4391^0x42db9f06) ==0
(((input_0*17)+(input_1*13)+((input_0*input_0)*2))%0x5E2F4391^^0x35368926) ==0
(((input_2*88)+((input_2*input_2)*5)-((input_0*input_2)*5))%0x5E2F4391^^0x509a3978)==0
(((input_3*232)+((input_2*input_2)*5)-((input_3*input_2)*4))%0x5E2F4391^^0x1ebfa92f)==0
((((input_4*input_4)*16)+(input_4*8)-((input_3*input_3)*35))%0x5E2F4391^^0x555cc98c)==0
88* input[1] + 6* input[0]* input[1] + -3* input[0]* input[0] mod 0x5E2F4391 == 0x42DB9F06
17* input[0] + 13* input[1] + 2* input[0]* input[0] mod 0x5E2F4391 == 0x35368926
88* input[2] + 5* input[2]* input[2] + -5* input[0]* input[2] mod 0x5E2F4391 == 0x509A3978
232* input[3] + 5* input[2]* input[2] + -4* input[2]* input[3] mod 0x5E2F4391 == 0x1EBFA92F
16* input[4]* input[4] + 8* input[4] + -35* input[3]* input[3] mod 0x5E2F4391 == 0x555CC98C
由于神秘原因z3无法解出
from z3 import *
# Define modulus
modulus = 0x5E2F4391
# Define input variables as 32-bit bit-vectors
input_vars = [BitVec(f'input[{i}]', 32) for i in range(5)]
# Define equations
eq1 = (88 * input_vars[1] + 6 * input_vars[0] * input_vars[1] - 3 * input_vars[0] * input_vars[0]) % modulus == 0x42DB9F06
eq2 = (17 * input_vars[0] + 13 * input_vars[1] + 2 * input_vars[0] * input_vars[0]) % modulus == 0x35368926
eq3 = (88 * input_vars[2] + 5 * input_vars[2] * input_vars[2] - 5 * input_vars[0] * input_vars[2]) % modulus == 0x509A3978
eq4 = (232 * input_vars[3] + 5 * input_vars[2] * input_vars[2] - 4 * input_vars[2] * input_vars[3]) % modulus == 0x1EBFA92F
eq5 = (16 * input_vars[4] * input_vars[4] + 8 * input_vars[4] - 35 * input_vars[3] * input_vars[3]) % modulus == 0x555CC98C
# Create solver and add equations
solver = Solver()
solver.add(eq1, eq2, eq3, eq4, eq5)
# Check satisfiability and solve
if solver.check() == sat:
model = solver.model()
solution = [model[input_vars[i]].as_long() for i in range(5)]
else:
solution = "No solution found"
print(solution)
看到大佬的解法,观察等式1和等式2 可以构造关于input_1的等式,直接用sagemath开根求解
modulu=0x5E04391
R.<x1> = Zmod(modulu)[]
x2=(0x35368926-0x11*x1-2*x1^2)/0xd
f=-3*x1^2+88*x2+6*x1*x2--0x42DB9F06
x1,_=f.roots()[0]
R.<x2> = Zmod(modulu)[]
f=2*x1*x1+13*x2+17*x1-0x35368926
x2,_=f.roots()[0]
同理去解x3,x4,x5
x1 = 862152290
x2 = 53932501 + 0x5E2F4391
x3 = 962670904
x4 = 859320929
x5 = 50524140 + 0x5E2F4391
3cfbaf5f9a18382aa23}
也可以利用爆破,构造x1的等式之后, 我们假设是由16进制字符的形式 组成
代码留着学习
#include <stdint.h>
#include <stdio.h>
#define P 0x5e2f4391
void any_conv(char *p, uint32_t n) {
const char *table = "0123456789abcdef"; // v5 }
const int base = 16; // v5 17
const int outsize = 8; // 4
for (int i = 0; i < outsize; i++) {
int v = n % base;
p[outsize - 1 - i] = table[v];
n = n / base;
}
}
void solve() {
char buf[9] = {0};
// 3cfbaf5f9a18382aa23}
uint64_t v1 = 0x33636662;
uint64_t v2 = 0x61663566;
uint64_t v3 = 0x39613138;
uint64_t v4 = 0x33383261;
uint64_t v5 = 0x6132337D;
for (uint32_t x = 0; ; x++) {
any_conv(buf, x);
if (x % 0x100000 == 0) {
printf("\r%08X", x);
fflush(stdout);
}
v1 = *(uint32_t *)&buf[0];
v2 = *(uint32_t *)&buf[4];
//v3 = *(uint32_t *)&buf[0];
//v4 = *(uint32_t *)&buf[4];
//v5 = *(uint32_t *)&buf[0];
uint64_t res1 = (((v2 * 0x58 + v1 * v2 * 0x6 - v1 * v1 * 0x3)) % P); // 0x42DB9F06
uint64_t res2 = (((v1 * 0x11 + v2 * 0xd + v1 * v1 * 0x2)) % P); // 0x35368926
uint64_t res3 = (((v3 * 0x58 + v3 * v3 * 0x5 - v1 * v3 * 0x5)) % P); // 0x509A3978
uint64_t res4 = (((v4 * 0xe8 + v3 * v3 * 0x5 - v4 * v3 * 0x4)) % P); // 0x1EBFA92F
uint64_t res5 = (((v5 * 0x8 + v5 * v5 * 0x10 - v4 * v4 * 0x23)) % P); // 0x555CC98C
if (res1 == 0x42DB9F06 && res2 == 0x35368926) {
printf("\n\n%s: %08X %08X\n", buf, (uint32_t)v1, (uint32_t)v2);
break;
}
// if (res3 == 0x509A3978 && res4 == 0x1EBFA92F && res5 == 0x555CC98C) {
// printf("\n\n%s: %08X %08X %08X\n", buf, (uint32_t)v3, (uint32_t)v4, (uint32_t)v5);
// break;
// }
}
}
int main() {
solve();
}
ez_vm
工程量太大了,待复现
apk2solve
安卓逆向,待学习