Re1:RE1
State:Solved
签到题,没啥好说的,OD直接跟入提字符串即可。
flag:BUPT{R3_1s_qu17e_3!mple:)}
Re2:RE2
State:Solved
按惯例,直接拖入IDA,F5
刚开始看到这个结构有点懵逼,跟进函数分析可以得到如图结构
跟进sub_401150可以发现sub_401000是处理函数,但是被加密了
.text:00401008 dword_401008 dd 5555554Dh, 6515DE6Bh, 15E35A6Bh, 0A910DC57h, 0D0A910DEh
.text:00401008 dd 3F522095h, 56B2BD55h, 32E45555h, 0E70AE506h, 20DE0330h
.text:00401008 dd 0B318DD5Dh, 0DDBE18DDh, 9302A318h, 931A8910h, 931D8810h
.text:00401008 dd 93168B10h, 93128A10h, 932EB510h, 931FB410h, 9337B710h
.text:00401008 dd 0DD3FB610h, 1093B110h, 109361B0h, 10DD33B2h, 0BC00DDBDh
.text:00401008 dd 17BF1093h, 93B910DDh, 932CB810h, 0DD63BB10h, 1093BA10h
.text:00401008 dd 109327A5h, 109334A4h, 0DD25A7h, 0A11093A6h, 0A0109339h
.text:00401008 dd 0A2109336h, 0AD109328h, 0DF9C6655h, 34696451h, 2F694229h
.text:00401008 dd 0EB5A462Ah, 1BDD695h, 55554FEAh, 0AAA2CC55h, 0BE3497D5h
.text:00401008 dd 29146961h, 2A0F6942h, 95EB5A46h, 0EA61BDD6h, 5555554Fh
.text:00401008 dd 0D5AAA2CCh, 4CBE1497h, 4D296569h, 412A6C69h, 0D695EB5Ah
.text:00401008 dd 5FEA76BDh, 0CC555555h, 97D5AAA2h, 6441DD65h, 49ACD614h
.text:00401008 dd 10D8F029h, 0DF45DF89h, 6F9FDF4Bh, 0D1792086h, 0DF43219Ch
.text:00401008 dd 0BDF5405h, 6F9FDF54h, 0D6492086h, 93D65795h, 209CD157h
.text:00401008 dd 66956689h, 5A95D09Ch, 0B0A94C0h, 0DE0E94DFh, 4E9608B0h
.text:00401008 dd 8DD60A95h, 0D09C66AAh, 94C05A95h, 0E94DF0Bh, 0C308B0DEh
.text:00401008 dd 2 dup(90909090h)
解密过程在子函数sub_4011C0中
这里进行了一些骚操作,把代码块异或0x55,块大小327(0x401000至0x401147)
用IDAPython逆回去即可
exp1:
from idaapi import *
for i in range(0x401000,0x401147):
PatchByte(i,Byte(i)^0x55)
重新构造函数(CreatFunction),即可得到
char __usercall sub_401026@<al>(int a1@<ebp>)
{
const char *v1; // esi
signed int v2; // ecx
char v3; // al
char v4; // dl
char result; // al
v1 = *(a1 + 8);
*(a1 - 26) = 'g';
*(a1 - 21) = 'g';
*(a1 - 10) = 'g';
*(a1 - 36) = 'O';
*(a1 - 35) = 'H';
*(a1 - 34) = 'C';
*(a1 - 33) = 'G';
*(a1 - 32) = '{';
*(a1 - 31) = 'J';
*(a1 - 30) = 'b';
*(a1 - 29) = 'j';
*(a1 - 28) = '_';
*(a1 - 27) = '4';
*(a1 - 25) = 'f';
*(a1 - 24) = '_';
*(a1 - 23) = 'e';
*(a1 - 22) = 'B';
*(a1 - 20) = '_';
*(a1 - 19) = 'y';
*(a1 - 18) = '6';
*(a1 - 17) = '_';
*(a1 - 16) = 'r';
*(a1 - 15) = 'a';
*(a1 - 14) = 'p';
*(a1 - 13) = 'e';
*(a1 - 12) = 'l';
*(a1 - 11) = 'c';
*(a1 - 9) = '}';
*(a1 - 8) = '\0';
v2 = 0;
do
{
v3 = v1[v2];
if ( v3 >= 97 && v3 <= 122 )
{
v4 = (v3 - 84) % 26 + 97;
LABEL_11:
v1[v2] = v4;
goto LABEL_12;
}
if ( v3 >= 65 && v3 <= 90 )
{
v4 = (v3 - 52) % 26 + 65;
goto LABEL_11;
}
if ( v3 >= 48 && v3 <= 57 )
{
v4 = (v3 - 35) % 10 + 48;
goto LABEL_11;
}
LABEL_12:
++v2;
}
while ( v2 < 28 );
if ( !strcmp((a1 - 36), v1) )
result = nullsub_2();
else
result = 1;
return result;
}
flag :OHCG{Jbj_4gf_eBg_y6_rapelcg}
再用脚本跑一下
exp2:
Plain_Text = 'OHCG{Jbj_4gf_eBg_y6_rapelcg}'
def fun(Plain_Text,shift):
Cipher_Text = ''
for i in Plain_Text:
if ord(i) in range(ord('A'),ord('Z')+1):
Cipher_Text += chr((ord(i)-ord('A')+shift)%26+ord('A'))
elif ord(i) in range(ord('a'),ord('z')+1):
Cipher_Text += chr((ord(i)-ord('a')+shift)%26+ord('a'))
elif ord(i) in range(ord('0'),ord('9')+1):
Cipher_Text += chr((ord(i)-ord('0')+shift)%10+ord('0'))
else:
Cipher_Text += i
print Cipher_Text
fun(Plain_Text,-13)
得到flag为BUPT{Wow_1ts_rOt_l3_encrypt}
Re3:RE3
State:Unsolved
这里复制的官方解(实在没时间去研究了,距高考80+天,理综还在270苟延残喘,Orz
程序加了壳,壳是变形的upx壳,脱壳找到oep,dump内存。oep位置如下图:
分析dump内存,查看main函数:
程序获取了自身一个名为BIN的资源,将其带入了0x401110函数。
程序对获取到的资源pSource进行了Size次异或0x77,即解密,对解密后的资源进行一系列和PE结构相关的操作,即内存释放DLL,其中涉及判断是否该资源为DLL,将资源以内存布局加载,修改IAT表以及重定位RELOC表,最后从DllMain函数启动。其中有两处反调试,如果调试,需要留意。
获取解密后的DLL,IDA进行分析:
分析线程函数0x10001000
11个未知数,每个未知数4字节,11个方程求解,脚本如下:
from z3 import *
import struct
cmpValue = [3350593028, 3187659634, 1962716233, 1695120199, 2164708281, 281870293, 4234765510, 1710951488, 3280612146, 907270479, 3620629970]
randNum = [130, 35, 99, 184, 1, 60, 50, 24, 27, 209, 161, 56, 5, 192, 46, 177, 128, 45, 141, 30, 201, 80, 161, 85, 88, 206, 148, 55, 139, 154, 177, 239, 173, 25, 37, 25, 153, 220, 33, 142, 155, 195, 64, 184, 231, 31, 55, 64, 251, 95, 28, 129, 7, 93, 188, 181, 212, 123, 161, 124, 160, 156, 76, 232, 239, 156, 138, 128, 201, 165, 210, 92, 37, 189, 68, 189, 17, 18, 151, 31, 171, 205, 233, 140, 80, 70, 214, 16, 250, 162, 89, 127, 230, 123, 76, 80, 244, 153, 94, 197, 36, 192, 95, 99, 75, 227, 112, 1, 93, 118, 69, 198, 29, 221, 148, 15, 166, 98, 44, 181, 56]
s = Solver()
a = [BitVec("a%d"%i, 32) for i in range(11)]
for j in range(11):
calValue = 0
for i in range(11):
calValue += a[i]*randNum[11*j+i]
calValue &= 0xffffffff
s.add(calValue == cmpValue[j])
while(s.check() == sat):
m = s.model()
for i in a:
print m[i],
print ""
exp = []
for val in a:
exp.append(val != m[val])
s.add(Or(exp))
flagint = "1414550850 1819235195 1735289206 1848656735 1634890805 1937010225 1985169759 1601794661 1702129201 1949656434 2103930417"
tmp = flagint.split(" ")
flag = ""
for i in tmp:
val = (int(i))
# print val
tmp = struct.pack("<I",val)
flag += tmp
print flag
可求出两组解,其中一组解均为可见字符,另外一组舍弃。
得到flag为BUPT{Solving_C0n5tra1nts_ISvery_1ntere5t1ng}Web请见buptbupt官方题解(计划于2019/3/17搬运)
小结:这次线上题比去年略难,re2看了好一会才反应过来(毕竟半年没做逆向题),按这成绩也能苟进线下,因为高三了得收收心就没报名。总的来说题目质量很高,北邮师傅们幸苦了,今年9月见(ง •_•)ง