练习16~
normal16
password1


因为前面有个提取数字,所以可以确定这个六位密码都是数字,SHA1之后比较,暴力即可
对照:https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id
import hashlib
a=[]
for i in range(32,128):
a.append(chr(i))
for i0 in a:
for i1 in a:
for i2 in a:
for i3 in a:
for i4 in a:
for i5 in a:
s=i0+i1+i2+i3+i4+i5+"123321@DBApp"
if hashlib.md5(s.encode("utf8")).hexdigest().upper()=="27019e688a4e62a649fd99cadaafdb4e":
print(i0+i1+i2+i3+i4+i5)
break
#123321
password2
同上,是md5,但是因为没有是数字的限制,暴力的话复杂度就太高了
所以先不管,看下面的比较函数

发现是首先查找名为“AAA”的资源并取出数据,然后和输入异或,之后生成了个rtf文件
大概就是答案=AAA里的前六个数据^rtf文件数据格式的前六个字符({\rtf1)
使用ResourceHacker软件查看资源,得到前六个数据为0x5,0x7D,0x41,0x15,0x26,0x1

b=[0x05,0x7D,0x41,0x15,0x26,0x01]
ss="{\\rtf1"
pw=""
for i in range(6):
pw+=chr(b[i]^ord(ss[i]))
print(pw)
#~!3a@0
输出Error之后会生成一个rtf文件,里面是flag


normal17

前面有::的变量是全局变量
看起来是个顺序,但是CreateThread,会创建新线程
大概就是可以用 WaitForSingleObject 等待互斥体的使用权(ownership)空闲出来,并获取使用权,然后再访问和其他线程共享的资源,访问完后,用 ReleaseMutex 释放使用权,给其他线程使用的机会
然后dword_418008初始29,判断是-1,显然这两个函数交替进行了多次
第一个是减下标然后这样操作一下

第二个只有减下标,也就是偶数位不变,奇数位操作一下
然后最后很朴素的比较了一下

不知道为啥off_418004点进去没有值,是从字符串窗口一路X找到的
s1="TOiZiZtOrYaToUwPnToBsOaOapsyS"
s2="QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
f=""
for i in range(len(s1)):
if i%2==0:
f+=s1[i]
else:
if (ord(s1[i])>=97) and (ord(s1[i])<=122):
f+=chr(s2.find(s1[i])+38)
else:
f+=chr(s2.find(s1[i])+96)
print(f)
#flag{ThisisthreadofwindowshahaIsES}
normal18
要求welcomebeijing对应的密码

两个while的结束条件是isalnum判断是否全是字母数字
loc_9311A0无法反编译,盲猜是给成功和失败的两种字符串赋值


sub_931830里的操作有点类似RC4加密,变化后的v17为dbappsec
然后动态调试找arr,先把两个if的jz改成jnz,然后进行程序的跟进,把每次循环使用到的arr记录下来
脚本
arr=[0x2A,0xD7,0x92,0xE9,0x53,0xE2,0xC4,0xCD]
str="dbappsec"
ans=""
for i in range(len(arr)):
arr[i]=ord(str[i])^arr[i]
ans+="%X"%arr[i]
print(ans)
# 4EB5F3992391A1AE
normal19
一开始因为花指令F5不出来,确定无效指令的位置
arr = [[0x4009A9,0x4009C7],[0x4009E0,0x4009FE],[0x400ACA,0x400AE8],[0x400B1A,0x400B38],[0x400B65,0x400B92],[0x400BEF,0x400C00]]
for i in range(len(arr)):
for j in range(arr[i][0],arr[i][1]):
ida_bytes.patch_byte(j,0x90)#IDA75里这个函数和其他版本的写法不一样
然后动态调试,发现有很多goto exit的地方,nop掉

arr = [[0x400972,0x400978], [0x400987,0x40098D],[0x400A2F,0x400A35],[0x400A77,0x400A7D],[0x400AAB,0x400AB1],[0x400BBC,0x400BC2]]
for i in range(len(arr)):
for j in range(arr[i][0],arr[i][1]):
ida_bytes.patch_byte(j,0x90)
然后在这里下断点

输入0123456789abcdefghi根据输出判断是怎么打乱的
脚本
s1="0123456789abcdefghi"
s2="8f6c90e1dg237abh5i4"
s="S@yRtfTl0+ag-L_3M}{"
ans=""
for i in range(len(s)):
ans+=s[s2.find(s1[i])]
print(ans)
# flag{My-StL_R0T@+3}
normal20

顺序累加,减回去就行
s=[0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x7B, 0x7C, 0x7D, 0x7E]
a=[0x72, 0xE9, 0x4D, 0xAC, 0xC1, 0xD0, 0x24, 0x6B, 0xB2, 0xF5, 0xFD, 0x45, 0x49, 0x94, 0xDC, 0x10, 0x10, 0x6B, 0xA3, 0xFB, 0x5C, 0x13, 0x17, 0xE4, 0x67, 0xFE, 0x72, 0xA1, 0xC7, 0x04, 0x2B, 0xC2, 0x9D, 0x3F, 0xA7, 0x6C, 0xE7, 0xD0, 0x90, 0x71, 0x36, 0xB3, 0xAB, 0x67, 0xBF, 0x60, 0x30, 0x3E, 0x78, 0xCD, 0x6D, 0x35, 0xC8, 0x55, 0xFF, 0xC0, 0x95, 0x62, 0xE6, 0xBB, 0x57, 0x34, 0x29, 0x0E,3]
f=''
n=len(a)
m=len(s)
for i in range(0,32):
nw=a[i]
for j in range(0,i):
# print(j,i-j)
nw=((nw-(ord(f[j])^s[i-j]))%128+128)%128
nw^=s[0]
# print(nw)
f+=chr(nw)
l1=a[n-1]^s[m-1]
l2=(a[n-2]-(l1^s[m-2]))^s[m-1]
f+=chr(l2)
f+=chr(l1)
print(f)
#SYC{4+mile+b3gin+with+sing1e+step}
normal21

先动态找rc4异或的8个值
断在这里,根据v9v10的值从v5[]里面找对应的值

然后暴力sub_401950的解
#include<iostream>
#include<cstdio>
using namespace std;
int v1[10];
int ck()
{
int dword_40F020=0x8A;
int dword_40F024=0x1A1;
int dword_40F028=0x12A;
int dword_40F02C=0x269;
int dword_40F030=0x209;
int dword_40F034=0x68;
int dword_40F038=0x39F;
int dword_40F03C=0x2C8;
int i=0;
do
{
switch ( v1[i] )
{
case 0:
dword_40F028 &= dword_40F038;
dword_40F02C *= dword_40F028;
break;
case 1:
if ( !dword_40F02C )
return 0;
dword_40F028 /= dword_40F02C;
dword_40F024 += dword_40F034;
break;
case 2:
dword_40F030 ^= dword_40F034;
dword_40F03C += dword_40F020;
break;
case 3:
dword_40F03C -= dword_40F030;
dword_40F030 &= dword_40F024;
break;
case 4:
dword_40F034 *= dword_40F020;
dword_40F02C -= dword_40F038;
break;
case 5:
dword_40F020 ^= dword_40F02C;
dword_40F038 -= dword_40F03C;
break;
case 6:
if ( !dword_40F03C )
return 0;
dword_40F034 |= dword_40F024 / dword_40F03C;
dword_40F024 /= dword_40F03C;
break;
case 7:
dword_40F038 += dword_40F028;
dword_40F034 |= dword_40F024;
break;
case 8:
dword_40F020 *= dword_40F02C;
dword_40F030 -= dword_40F03C;
break;
case 9:
dword_40F028 += dword_40F034;
dword_40F02C ^= dword_40F030;
break;
default:
return 0;
}
++i;
}
while ( i < 8 );
int result = (dword_40F038 == 231)
+ (dword_40F034 == 14456)
+ (dword_40F030 == 14961)
+ (dword_40F02C == -13264)
+ (dword_40F028 == 16)
+ (dword_40F024 == 104)
+ (dword_40F020 == -951) == 7;
if ( dword_40F03C != -239 )
return 0;
return result;
}
void dfs(int w)
{
if(w==8)
{
if(ck())
{
for(int i=0;i<8;i++)
printf("%d,",v1[i]);
// exit(0);
}
return;
}
for(int i=0;i<=9;i++)
{
v1[w]=i;
dfs(w+1);
v1[w]=-1;
}
}
int main()
{
dfs(0);
return 0;
}
//6,1,4,9,5,0,7,2,
然后写解密脚本
a=[0x7C,0xAB,0x2D,0x91,0x2F,0x98,0xED,0xA9]
b=[6,1,4,9,5,0,7,2]
for i in range(len(a)):
print(hex(a[i]^b[i])[2:],end='')

normal22
查壳,然后用upxshell脱壳
然后就是压一下串和已知串比较




s=[0x00000050, 0x000000C6, 0x000000F1, 0x000000E4, 0x000000E3, 0x000000E2, 0x0000009A, 0x000000A1,167,222,218,70,171,46,255,219]
f=''
for i in range(16):
s[i]-=1
a=s[i]>>4
b=s[i]&15
if a<=9:
a+=48
else:
a+=87
if b<=9:
b+=48
else:
b+=87
f+=chr(a)+chr(b)
print(f)
#4fc5f0e3e2e199a0a6ddd945aa2dfeda
normal24

就是把输入操作了一下进行xxtea加密,动态得到传入参数分别是输入字符串,输入字符串的前四个字节,00000..,加密后数组的大小
然后用z3逆出来后面的部分对加密后字符串的操作

from z3 import *
a=[0xCE,0xBC,0x40,0x6B,0x7C,0x3A,0x95,0xC0,0xEF,0x9B,0x20,0x20,0x91,0xF7,0x02,0x35,0x23,0x18,0x02,0xC8,0xE7,0x56,0x56,0xFA]
s=Solver()
f=[BitVec('%d'%i ,8) for i in range(24)]
for i in range(1,24):
if i//3>0:
nw=f[i]
for j in range((int)(i/3)):
nw^=f[j]
f[i]=nw
for i in range(24):
s.add(f[i]==a[i])
if s.check()==sat:
result=s.model()
print(result)
else:
print('unsat')
然后找出换位前的数组
a=[206,188,64,165,178,244,231,178,157,169,18,18,200,174,91,16,6,61,29,215,248,220,220,112]
b=[2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
f=[0]*24
for i in range(24):
f[b[i]]=a[i]
print(f)
import struct
_DELTA = 0x9E3779B9
def _long2str(v, w):
n = (len(v) - 1) << 2
if w:
m = v[-1]
if (m < n - 3) or (m > n):
return ''
n = m
s = struct.pack('<%iL' % len(v), *v)
return s[0:n] if w else s
def _str2long(s, w):
n = len(s)
m = (4 - (n & 3) & 3) + n
s = s.ljust(m, "\0")
v = list(struct.unpack('<%iL' % (m >> 2), s))
if w:
v.append(n)
return v
def decrypt(str, key):
if str == '': return str
v = _str2long(str, False)
k = _str2long(key.ljust(16, "\0"), False)
n = len(v) - 1
z = v[n]
y = v[0]
q = 6 + 52 // (n + 1)
sum = (q * _DELTA) & 0xffffffff
while (sum != 0):
e = sum >> 2 & 3
for p in xrange(n, 0, -1):
z = v[p - 1]
v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff
y = v[p]
z = v[n]
v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff
y = v[0]
sum = (sum - _DELTA) & 0xffffffff
return _long2str(v, True)
if __name__ == "__main__":
key = "flag"
data1 = [188, 165, 206, 64, 244, 178, 178, 231, 169, 18, 157, 18, 174, 16, 200, 91, 61, 215, 6, 29, 220, 112, 248, 220]
s = "".join(map(chr, data1))
s = decrypt(s, key)
print(repr(s))
#flag{CXX_and_++tea}
normal25
字符串窗口没用,S+F7找段

跟进去,找到读入


然后根据fg盲猜异或值是'flag',写脚本解密就行
a=[64,53,32,86,93,24,34,69,23,47,36,110,98,60,39,84,72,108,36,110,114,60,50,69,91]
b=[ ord('f') ^ 64,ord('l') ^ 53,ord('a')^32,ord('g')^86]
f=""
for i in range(len(a)):
f+=chr(a[i]^b[i % 4])
print(f)
#flag{Act1ve_Defen5e_Test}
normal26

先用输入0123456789abcdefghijklmnopqrstu动态找出打乱flag的对应关系
然后暴力解出这一部分

得到:private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)
根据https://www.cnblogs.com/CodeMIRACLE/p/5343660.html,还原出v2为'?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'。
脚本:
s='1234567890-=!@#$%^&*()_'
s1='(_@4620!08!6_0*0442!@186%%0@3=66!!974*3234=&0^3&1@=&0908!6_0*&'
s2='55565653255552225565565555243466334653663544426565555525555222'
ot=""
for i in range(62):
for j in range(1,127):
a=j%23
b=j//23
if s[a]==s1[i]:
if s[b]==s2[i]:
ot+=chr(j)
print(ot)
#private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)
a='0123456789abcdefghijklmnopqrstu'
c=[0x66,0x67,0x37,0x68,0x69,0x38,0x33,0x6A,0x6B,0x39,0x6C,0x6D,0x61,0x34,0x31,0x6E,0x6F,0x62,0x70,0x71,0x63,0x35,0x72,0x73,0x64,0x74,0x75,0x65,0x36,0x32,0x30,0x0]
b=''
for i in c:
b+=chr(i)
str4='?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z'
f=""
for i in range(len(a)):
f+=str4[b.find(a[i])]
print(f)
#Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP
normal27
逆成py是
# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: E:/Code/python/Geek-python/python1.py
# Compiled at: 2019-10-22 16:59:55
import struct, time
def b(a):
return a & 18446744073709551615
def c(str):
return struct.unpack('<Q', str)[0]#打包
def d(a):
for i in range(64):
a = a * 2
if a > 18446744073709551615:
a = b(a)
a = b(a ^ 12682219522899977907)
return a
if __name__ == '__main__':
cmp_data = [
7966260180038414229, 16286944838295011030, 8598951912044448753, 7047634009948092561, 7308282357635670895]
input = raw_input('plz input your flag:')
if len(input) % 8 != 0:
for i in range(8 - len(input) % 8):
input += '\x00'
arr = []
for i in range(len(input) / 8):
value = d(c(input[i * 8:i * 8 + 8]))
arr.append(value)
for i in range(5):
if arr[i] != cmp_data[i]:
print 'fail'
time.sleep(5)
exit()
print 'success'
time.sleep(5)
exit()
# okay decompiling normal27.pyc
因为异或的是奇数,前置操作又是左移,末尾为0,所以根据奇偶性可以判断有没有进if,然后反着来就行
import struct
a=[7966260180038414229, 16286944838295011030, 8598951912044448753, 7047634009948092561, 7308282357635670895]
f=''
for x in a:
for i in range(64):
if x%2==0:
x>>=1
else:
x=x^12682219522899977907
x=x+(1<<64)
x>>=1
f+=str((struct.pack('>Q',x)[::-1].strip()),encoding='utf-8')
print(f)
#Syc{L1fe_i5_sh0rt_y0u_n3ed_py7h0n}
normal28
源码:
# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: E:\CTF\Geek-python\python2\python2.py
# Compiled at: 2019-10-22 19:40:16
import struct, time
def fun(start, end, s):
a = 32310901
b = 1729
c = s
m = end - start#254
while True:
d = int((a * c + b) % m)
yield d
c = d
if __name__ == '__main__':
arr = [
77, 263, 394, 442, 463, 512, 667, 641, 804, 752, 885, 815, 1075, 1059, 1166, 1082, 1429, 1583, 1696, 1380,
1987, 2263, 2128, 2277, 2387, 2670, 2692, 3255, 3116, 3306, 3132, 3659, 3139, 3422, 3600, 3584, 3343, 3546,
3299, 3633, 3281, 3146, 2990, 2617, 2780, 2893, 2573, 2584, 2424, 2715, 2513, 2324, 2080, 2293, 2245, 2309,
2036, 1944, 1931, 1817, 1483, 1372, 1087, 1221, 893, 785, 697, 586, 547, 324, 177, 184]
flag = raw_input('plz input your flag:')
length = len(flag)
a = struct.unpack('<I', flag[length - 4:].encode())[0] & 255
b = []
c = fun(1, 255, a)
for i in range(32):
b.append(next(c))
d = [ 0 for i in range(72) ]
for i in range(length):
for j in range(32):
a = ord(flag[i]) ^ b[j]
d[(i + j)] += a
for i in range(len(d)):
if d[i] != arr[i]:
print 'fail'
time.sleep(5)
exit(0)
print 'success'
time.sleep(5)
exit(0)
# okay decompiling normal28.pyc
大概是根据flag%254生成一个数列,然后异或搞一下和arr比较
用z3来解决后面异或的部分,然后数列初始值枚举一下
from z3 import *
import time
def fun(start, end, s):
a=32310901
b=1729
c=s
m=end - start#254
while True:
d=int((a * c + b) % m)
yield d
c=d
def Z3(p):
s=Solver()
f=[BitVec(('x%d' % i),8) for i in range(41) ]
q=[77, 263, 394, 442, 463, 512, 667, 641, 804, 752, 885, 815, 1075, 1059, 1166, 1082, 1429, 1583, 1696, 1380,
1987, 2263, 2128, 2277, 2387, 2670, 2692, 3255, 3116, 3306, 3132, 3659, 3139, 3422, 3600, 3584, 3343, 3546,
3299, 3633, 3281, 3146, 2990, 2617, 2780, 2893, 2573, 2584, 2424, 2715, 2513, 2324, 2080, 2293, 2245, 2309,
2036, 1944, 1931, 1817, 1483, 1372, 1087, 1221, 893, 785, 697, 586, 547, 324, 177, 184]
r=[0 for i in range(72)]
for i in range(41):
for j in range(32):
a=f[i]^p[j]
r[i+j]+=a
for i in range(0,72):
s.add(r[i]==q[i])
if s.check()==sat:
model=s.model()
str=[chr(model[f[i]].as_long().real) for i in range(41)]
print("".join(str))
time.sleep(5)
exit()
else:
print("unsat")
if __name__ == "__main__":
for seed in range(0xff):
p=[]
r=fun(1, 255, seed)
for i in range(32):
p.append(next(r))
Z3(p)
normal29
源码
# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: E:/Syclover/python3.py
# Compiled at: 2019-11-03 13:29:35
from unicorn import *
from unicorn import arm_const as ac
import time
def Unicorn(input):
bytescode = b'\x08\xb0-\xe5\x04\xe0\x8d\xe5\x04\xb0\x8d\xe2\x10\xd0M\xe2\x10\x00\x0b\xe5\x14\x10\x0b\xe5\x000\xa0\xe3\x080\x0b\xe5\x000\xa0\xe3\x080\x0b\xe5\x1b\x00\x00\xea\x080\x1b\xe5\x010\x03\xe2\x00\x00S\xe3\n\x00\x00\n\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x07 \x82\xe2r \xef\xe6\x00 \xc3\xe5\t\x00\x00\xea\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x04 \x82\xe2r \xef\xe6\x00 \xc3\xe5\x080\x1b\xe5\x010\x83\xe2\x080\x0b\xe5\x080\x1b\xe5\x1e\x00S\xe3\xe0\xff\xff\xda\x000\xa0\xe3\x080\x0b\xe5\x17\x00\x00\xea\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x000\xd3\xe5\x0c0\x0b\xe5\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x10 \x82\xe2\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x00 \xc3\xe5\x080\x1b\xe5\x100\x83\xe2\x10 \x1b\xe5\x030\x82\xe0\x0c \x1b\xe5r \xef\xe6\x00 \xc3\xe5\x080\x1b\xe5\x010\x83\xe2\x080\x0b\xe5\x080\x1b\xe5\x0e\x00S\xe3\xe4\xff\xff\xda\x000\xa0\xe3\x080\x0b\xe5\x17\x00\x00\xea\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x000\xd3\xe5\x0c0\x0b\xe5\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x01 \x82\xe2\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x00 \xc3\xe5\x080\x1b\xe5\x010\x83\xe2\x10 \x1b\xe5\x030\x82\xe0\x0c \x1b\xe5r \xef\xe6\x00 \xc3\xe5\x080\x1b\xe5\x020\x83\xe2\x080\x0b\xe5\x080\x1b\xe5\x1d\x00S\xe3\xe4\xff\xff\xda\x140\x1b\xe5\x00\x00S\xe3\x01\x00\x00\x1a\x010\xa0\xe3\x04\x00\x00\xea\x140\x1b\xe5\x010C\xe2\x03\x10\xa0\xe1\x10\x00\x1b\xe5\x8f\xff\xff\xeb\x03\x00\xa0\xe1\x04\xd0K\xe2\x00\xb0\x9d\xe5\x04\xd0\x8d\xe2\x04\xf0\x9d\xe4'
cmp_data = [149, 187, 165, 189, 151, 176, 171, 165, 114, 180, 176, 161, 115, 181, 155, 174, 117, 163, 174, 115, 187, 161, 163, 175, 163, 116, 115, 176, 169, 99, 185]
def hook_code(mu, address, size, user_data):
if address == BASE + 420:
data = mu.mem_read(0, 31)
if [ data[i] for i in range(len(data)) ] == cmp_data:
print 'success'
time.sleep(5)
exit(0)
else:
print 'fail'
time.sleep(5)
exit(0)
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
BASE = 4194304
STACK_ADDR1 = 0
STACK_ADDR2 = 1024
STACK_SIZE = 1048576
mu.mem_map(BASE, 1048576)
mu.mem_map(STACK_ADDR1, STACK_SIZE)
mu.mem_write(STACK_ADDR1, input.encode())#写入输入到栈地址0处
mu.reg_write(ac.UC_ARM_REG_R0, 0) #栈地址存放在r0寄存器中,参数1
mu.reg_write(ac.UC_ARM_REG_R1, 11)#0xB放入r1寄存器中,参数2
mu.reg_write(ac.UC_ARM_REG_SP, STACK_ADDR2 - 1)
mu.mem_write(BASE, bytescode)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(BASE, BASE + 424)
if __name__ == '__main__':
input = raw_input('plz input your flag:')
Unicorn(input)
# okay decompiling normal29.pyc
用到了unicorn
https://bbs.pediy.com/thread-253868.htm
https://www.anquanke.com/post/id/95199#h2-18
先把bytescode生成二进制文件
def write(path,bytes):
file = open(path,'wb')
file.write(bytes)
file.close()
if __name__ == "__main__":
bytescode = b'\x08\xb0-\xe5\x04\xe0\x8d\xe5\x04\xb0\x8d\xe2\x10\xd0M\xe2\x10\x00\x0b\xe5\x14\x10\x0b\xe5\x000\xa0\xe3\x080\x0b\xe5\x000\xa0\xe3\x080\x0b\xe5\x1b\x00\x00\xea\x080\x1b\xe5\x010\x03\xe2\x00\x00S\xe3\n\x00\x00\n\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x07 \x82\xe2r \xef\xe6\x00 \xc3\xe5\t\x00\x00\xea\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x04 \x82\xe2r \xef\xe6\x00 \xc3\xe5\x080\x1b\xe5\x010\x83\xe2\x080\x0b\xe5\x080\x1b\xe5\x1e\x00S\xe3\xe0\xff\xff\xda\x000\xa0\xe3\x080\x0b\xe5\x17\x00\x00\xea\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x000\xd3\xe5\x0c0\x0b\xe5\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x10 \x82\xe2\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x00 \xc3\xe5\x080\x1b\xe5\x100\x83\xe2\x10 \x1b\xe5\x030\x82\xe0\x0c \x1b\xe5r \xef\xe6\x00 \xc3\xe5\x080\x1b\xe5\x010\x83\xe2\x080\x0b\xe5\x080\x1b\xe5\x0e\x00S\xe3\xe4\xff\xff\xda\x000\xa0\xe3\x080\x0b\xe5\x17\x00\x00\xea\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x000\xd3\xe5\x0c0\x0b\xe5\x080\x1b\xe5\x10 \x1b\xe5\x030\x82\xe0\x08 \x1b\xe5\x01 \x82\xe2\x10\x10\x1b\xe5\x02 \x81\xe0\x00 \xd2\xe5\x00 \xc3\xe5\x080\x1b\xe5\x010\x83\xe2\x10 \x1b\xe5\x030\x82\xe0\x0c \x1b\xe5r \xef\xe6\x00 \xc3\xe5\x080\x1b\xe5\x020\x83\xe2\x080\x0b\xe5\x080\x1b\xe5\x1d\x00S\xe3\xe4\xff\xff\xda\x140\x1b\xe5\x00\x00S\xe3\x01\x00\x00\x1a\x010\xa0\xe3\x04\x00\x00\xea\x140\x1b\xe5\x010C\xe2\x03\x10\xa0\xe1\x10\x00\x1b\xe5\x8f\xff\xff\xeb\x03\x00\xa0\xe1\x04\xd0K\xe2\x00\xb0\x9d\xe5\x04\xd0\x8d\xe2\x04\xf0\x9d\xe4'
write("D:/python3",bytescode)
然后拖进IDA32,

按C反汇编

一个简单的递归,传参分别是flag和11
脚本
def dfs(a,n):
s=""
s1=""
s2=""
for i in range(0,30,2):
s+=a[i+1]
s+=a[i]
s+=a[30]
s1+=s[16:]+s[15]+s[:15]
for i in range(31):
if(i%2):
s2+=chr(ord(s1[i])-7)
else:
s2+=chr(ord(s1[i])-4)
if(n==0):
print(s2)
return
dfs(s2, n - 1)
if __name__ == "__main__":
a=[149,187,165,189,151,176,171,165,114,180,176,161,115,181,155,174,117,163,174,115,187,161,163,175,163,116,115,176,169,99,185]
dfs("".join(map(chr,a)),11)
# Syc{Unic0rn_1s_r3al1y_ama21ng!}
normal31
前置条件是MessageBoxA已被hook
在字符串窗口找到success字符串,找引用没在main里,应该是这一部分被hook掉了

然后跳到AddVectoredExceptionHandler执行指针Handler所指向的函数

中间是sm4的密钥处理,SetUnhandledExceptionFilter(TopLevelExceptionFilter),这个API叫设置异常捕获函数
参数:lpTopLevelExceptionFilter ,函数指针。当异常发生时,且程序不处于调试模式(在vs或者别的调试器里运行)则首先调用该函数。
返回值:返回以前设置的回调函数。
又回到那个被hook住的MessageBoxW函数下方执行那个sm4加密

执行完了sm4加密之后,异常发生,又会回调到刚才SetUnhandledExceptionFilter设置的异常捕获函数的参数lpTopLevelExceptionFilter指针所指向的函数中继续执行
继续往下,发现Str又被改了

BASE64的编码表最终是yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx
from pysm4 import decrypt
#-------base64-----------------
diy_baes = 'yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx!'
base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
cipher = "1UTAOIkpyOSWGv/mOYFY4R!!"
new_cipher4 = ""
for i in range(0,len(cipher),2):
new_cipher4 += cipher[i+1]
new_cipher4 += cipher[i]
new_cipher = ""
for i in range(len(new_cipher4)):
new_cipher += base[diy_baes.find(new_cipher4[i])]
print(new_cipher)
#-------base64-----------------
#--------cipher_num-------------
byte = new_cipher.decode("base64")
cipher_num = ""
for i in range(len(byte)):
cipher_num += "%2x"%(ord(byte[i]))
cipher_num = int(cipher_num.replace(' ','0'),base=16)
print(cipher_num)
#--------cipher-------------
#-----------key_num----------
str = "where_are_u_now?"
key_num = ""
for i in range(len(str)):
key_num += "%x"%(ord(str[i]))
key_num = int(key_num,base=16)
print(key_num)
#-----------key----------
clear_num = decrypt(cipher_num, key_num)
print(hex(clear_num)[2:-1].decode('hex'))
#WdCVKQ3yQAYU9I0naQaHTg==
#119384314703134531538573762305905297230
#158720187958446400518369106772618082111
#SM4foRExcepioN?!
normal32
动态的时候F5两次可以把main里没编译出来的部分搞出来,不知道为啥……

这里是一个异或
然后进入加密函数




然后原样转回去,v36那里不知道为啥提取不出来hex,手动把负数转了一下
import struct
b=""
f=""
s="SWPU_2019_CTF"
r=[0xF80F37B3, 0x5DAEBCBC, 0x864D5ABA, 0xD3629744, 0x1624BA4F, 0x1A729F0B, 0x266D6865, 0x67C86BBA]
# r=[-133220429,1571732668,-2041750854,-748513468,371505743,443719435,644704357,1741188026]
a=[0xCA3E0C86, 0x19AED798, 0xA66B77E2, 0xB077A16A, 0x05379169, 0x307BF97A, 0x104B5A43, 0x28D47D86]
for i in range(8):
b+=str(struct.pack("<L",r[i]^a[i]),encoding="utf8")#编码!
for i in range(len(b)):
f+=chr(ord(b[i])^ord(s[i%len(s)]))
print(f)
#flag{Y0uaretheB3st!#@_VirtualCC}
浙公网安备 33010602011771号