XCTF攻防世界-逆向wp

to be a hardcore reverser

新手练习

re1

最简单的exe题…wp说直接strings就好,不过一开始字符串被打散了,不好直接看出来

试着直接符号执行,惊讶的是exe在ubuntu的angr里直接跑起来了,不过占资源太多被杀掉好几次,设置了系统参数也没办法解决,就放弃了

后来尝试了下IDA的动态调试,在cmp处下断点就解决了

game

一个游戏通关后输出flag的题

先在IDA中shift+F12查找字符串,发现the flag is,跟踪到输出处

认定前面没有陷阱之后,发现就是2个字符数组的异或…

还是得多刷题,一开始并没有想到查找字符串哎

Hello,CTF

一串硬编码的十六进制数据,转成字符串就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
#include<stdlib.h>
#include<string.h>


const char*s = "437261636b4d654a757374466f7246756e";
int num[] ={
0x43,0x72,0x61,0x63,0x6b,0x4d,0x65,0x4a,0x75,0x73,0x74,0x46,0x6f,0x72,0x46,0x75,0x6e
};

int main(int argc, char**argv) {
int len = strlen(s);
for (int i = 0; i < len; i += 2) {
printf("0x%c%c,", s[i], s[i + 1]);
}
//0x43,0x72,0x61,0x63,0x6b,0x4d,0x65,0x4a,0x75,0x73,0x74,0x46,0x6f,0x72,0x46,0x75,0x6e
for (int i = 0; i < 17; i++) {
printf("%c", num[i]);
}
//CrackMeJustForFun
return 0;
}

我就是要用C解…

open-source

给了源码,值得注意的是命令行参数的问题

比如输入./hash 1 2 3,这样argc==4

argv[0]=="./hash",argv[1]=="1",argv[2]=="2",argv[3]=="3"

不过我试了试直接符号执行,发现终于成功了一次…记录于符号执行-angr

simple2

从52pojie找了2个查壳工具,发现是upx壳,直接upx -d脱壳即可,flag是硬编码明文比较

logmein

题目名字的意思好像是一个远程接入软件

1

2

简单的异或题,不过一开始跑出来是乱码,后来看了网上的wp才发现…

IDA里字符串常量已经加上了转义符号,也就是说那串字符串里没有反斜杠

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char**argv){
long long num = 0x65626D61726168LL;
char* str = ":\"AL_RT^L*.?+6/46"; // len == 17
for(int i = 0;i<17;i++){
printf("%c",*((char*)&num+i%7)^str[i]);
//*(&num + i%7) -> num[i%7]
}
return 0;
}

本题也符合angr的适用范围

1
2
3
4
5
6
7
8
import angr
import claripy

proj = angr.Project("./logmein")
state = proj.factory.entry_state()
simgr = proj.factory.simgr(state)
simgr.explore(find=0x4007ac)
print simgr.found[0].posix.dumps(0)

insanity

虽然没完全理解程序逻辑,不过既然flag都明文存好了……

no_strings_attached

这题似乎牵涉到编码……wp说动态调,算了算了……

输出wprintf,应该是宽字节吧

我反正直接int当%c输出了…发现没啥问题

如果要解释一下的话…可能是这个编码在32bits的高24位都为0时,和ASCII等价吧

3

解密部分,看了好久…

总之就是38个字符都会减去某个数值x,x从一个5个数的数组中依次取

一旦x取到数组结束,那么再从头开始

于是用个取余就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int nums[38]={
5178, 5174, 5175, 5179, 5248, 5242, 5233, 5240, 5219,
5222, 5235, 5223, 5218, 5221, 5235, 5216, 5227, 5233,
5240, 5226, 5235, 5232, 5220, 5240, 5230, 5232, 5232,
5220, 5232, 5220, 5230, 5243, 5238, 5240, 5226, 5235,
5243, 5248
};

int nums2[5]={5121, 5122, 5123, 5124, 5125};

int main(int argc,char**argv){
for(int i = 0;i<38;i++){
printf("%c",nums[i] - nums2[i%5]);
}
//9447{you_are_an_international_mystery}
return 0;
}

csaw2013reversing2

程序不会执行到解密部分,patch改控制流即可

key-patcher好像有bug,还要我手动算jmp的偏移…

反正计算偏移时,减去的是当前指令的下一条指令的地址

基本思路就是:让程序执行解密部分,再控制跳转到MessageBox函数

4

getit

在0x400832处下断点,不断c就可以每次发现flag的一个字符

没什么意思

python-trade

pyc逆向题,pyc在线反编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import base64

def encode(message):
s = ''
for i in message:
x = ord(i) ^ 32
x = x + 16
s += chr(x)

return base64.b64encode(s)

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
print 'correct'
else:
print 'wrong'

解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
import base64

buf = base64.b64decode("XlNkVmtUI1MgXWBZXCFeKY+AaXNt")
flag = ""

for i in buf:
x = ord(i)
x -= 16
x ^= 32
flag += chr(x)

print flag

base64我还真懒得找C库……

maze

迷宫问题,参考链接

萌新入坑

reverse100

.NET平台的逆向,exe文件,题目名字叫apk…

网上找了个ILSpy,反编译

算了还是直接搜wp吧

程序会往本地31337端口发flag,于是用python写个监听的脚本

1
2
3
4
5
import BaseHTTPServer
server_address = ('127.0.0.1', 31337)
handler_class = BaseHTTPServer.BaseHTTPRequestHandler
httpd = BaseHTTPServer.HTTPServer(server_address, handler_class)
httpd.serve_forever()

就这么收到了flag,虽然不知道程序里具体flag在哪

原来直接nc就可以了…

1
nc -l 127.0.0.1 31337

rock

C++的题,输入一个string

5

后面的三个函数应该仅用于混淆

6

这个函数的第一个参数应该是一个类

1
2
3
4
5
a->vtable = 0x401bf0;
a->x = 0;
a->input_1 = std::string(input);
a->input_2 = std::string(input);
a->string3 = "FLAG23456912365453475897834567" + std::string(input);

虚表赋值,一个字段置0,后面2个字段保存输入的字符串,最后一个字段存放拼接的字符串

跟进下一个对此类进行操作的函数

7

首先检查长度为30,接下来是简单的字符操作

1
2
3
4
5
6
for(int i = 0; i < len; i++) {
a->input[i] = (a->input[i] ^ 0x50) + 20;
}
for(int j = 0; j < len; j++) {
a->input[i] = (a->input[i] ^ 0x10) + 9;
}

8

用于检查的函数,转换过后的字符串要等于类中最后一个字段保存的字符串

而最后输出的flag就是我们保存的input副本,也就是输入值

解密代码

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc,char**argv){
char* s = "FLAG23456912365453475897834567"; //len = 30
for(int i = 0;i<30;i++){
printf("%c",(((s[i]-9)^0x10)-20)^0x50);
}
return 0;
}

提交flag的时候题目有问题…

总结一下就是做C++逆向不要慌…

去掉无关信息还是可以看的

不过我不是很了解string这些的底层,指针引用等,逆向时只能选择相信出题人没有那么变态了

elf.re

就是angr的第一个例题,提交flag格式仍然不对

re-for-50-plz-50

mips架构的…

9

IDA不能反编译,不过这题就是硬编码字符串和0x37异或,至于复杂的题…以后再说吧

babyRE

做过的题,judge函数被异或加密了

10

IDC脚本

1
2
3
4
5
6
7
8
9
10
#include<idc.idc>
static decrypt(from,size,key){
auto i,x;
for(i=0;i<=size;i++){
x = Byte(from);
x = (x^key);
PatchByte(from,x);
from = from + 1;
}
}

IDC>decrypt(0x600B00,181,0xC);

然后 U C P三连,F5即可

取消定义,看作代码,再看作函数过程

不过平台上flag格式又不对

zorro_bin

一开始理解错解题思路了

11

第一个输入的数k,然后就让输入k个值,一堆异或之后得到seed,这里需要注意到,因为seed的取值会被检验,取值集合是固定的,而一堆数异或就等价于一个数异或,也就是说这里k的取值无关紧要,因此我们令k=1即可

12

然后就是常见的随机种子固定,rand()的输出序列固定了

是可以爆破出所有的seed值,也就是k=1时输入的那个值,但是没有必要,因为得到了取值集合之后还是需要一个一个喂给程序

由于范围不大,我们直接爆破1-65535即可,不符合的值会让程序直接退出,没有必要先爆破可能的seed值再喂

其中只有输入预期的seed值时,才会通过MD5检验,可以考虑把jz改成jmp,但是没有必要,因为输入了错误的seed时,flag也是乱码,让程序直接退出也是一样的

最后给出wp中的shell脚本

有时间学一下shell脚本的使用,想着可以用pwn的思路起进程,不过比较麻烦

1
for i in $(seq 1 65535); do echo -e "1\n$i" | ./zorro_bin | grep -i nullcon ; done

这个脚本”猜测”了flag中会出现nullcon,也可以人工看……

最后输出 The flag is nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}

最后的思考:MD5占用了程序运行的很多时间,如果seed的取值范围更大,可以考虑nop掉

pingpong待做

BCTF2017的题,android没有接触过,先放一下了

wp1

wp2

licensable待做

感觉应该要黑盒逆,以前熟悉过的OD现在全忘了…

存着吧,附:wp

RM

序列号就是flag

13

baby_flash-222待做

官方wp

C++编译到flash的题目,wp中有swf文件的反编译,待做

easyre-153

IDA打开发现没有main,我又忘记查壳

14

upx -d后,程序流程中输入当前子进程的pid

15

16

然后就会输出假的flag……

在IDA里有这一段

17

lol是输出的函数,不过没看出来buf和输出有什么关联

18

好吧还是看writeup吧

19

因为1!=0,所以永远会跳转到loc_80486D3,可以修改跳转指令,也可以直接通过lol的算法取得

这可能是upx加壳后的问题,反编译后看不到这一段,还是得看看汇编

flag在这段”花指令”中……还是太年轻了

修改跳转指令后,运行输入pid即可得到flag

另外,发现(看了wp以后猜测)这段数据经过一些算法就是flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char**argv) {
const char*a1 = "69800876143568214356928753";
char flag[7];
flag[0] = 2 * a1[1];
flag[1] = a1[4] + a1[5];
flag[2] = a1[8] + a1[9];
flag[3] = 2 * a1[12];
flag[4] = a1[18] + a1[17];
flag[5] = a1[10] + a1[21];
flag[6] = a1[9] + a1[25];
for (int i = 0; i < 7; i++) {
printf("%c", flag[i]);
}
return 0;
}

直接当作char型运算即可,不用转换

总结一下: 查壳,遇到假flag时看看汇编,也许flag在”花指令”中

re2

C++的string的逆向题,命令行参数输入

其中遍历一个字符串时,从begin()开始,到end()结束,迭代器如果等于end(),就表示遍历结束

这里应该是迭代器相同就退出,而不是迭代器中的字符相同

一顿分析以后发现,密文:

L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t

20

正确的flag就是密文错位后的结果

不过这里内层的数组好像有点问题,因为是逐字符比较,gdb动态调一下

把跳转指令patch一下,比较失败也继续执行,这样我们只要不断从rax中获取数值就可以拼出flag了

ALEXCTF{W3_L0v3_C_W1th_CL45535}

wp链接

动态调试加上脚本爆破,脚本我不会写……

逐字符比较,尝试patch掉跳转指令,直接动态调试

Catch_Me待做

题目给的附件有点问题好像

参考链接

参考链接

wp完全看不懂

rev100

解压后看起来是个十六进制文件

xxd让它恢复到原来的样子

xxd -r -p rev100

好吧,大部分都是垃圾文字,但是中间夹杂着一下ASCII字母,可以看到flag…什么的。每个’h’后面都有两个有用的,我们把他们挑出来:

1
bash $ sed "s/ / /g" rev100 | xxd -r | strings -n 1 | grep '^h' | cut -c 2- | tr -d '\n'

flag{poppopret}

这题…乏趣

reverseme120

这个题卡了很久……经验不足

21

第一个函数对输入字符串v11进行了操作,不过很迷……根本看不出来它在干嘛

当时就一直在逆这部分的逻辑

后来看了wp才发现其中一段关键代码与base64有关

22

wp说显然这个这一串数组是base64的码表…对不起我不认识

23

黑盒测出v13就是base64加密后的结果

24

这里TM竟然是分两部分异或0x25……

最后解密就简单了….

把固定的字符串you_know_how_to_remove_junk_code异或0x25

得到\JPzNKJRzMJRzQJzW@HJS@zOPKNzFJA@

再base64加密,XEpQek5LSlJ6TUpSelFKeldASEpTQHpPUEtOekZKQUA

base64的原理之前了解不多,试了试”@@@@”这种也可以加密…

关于做题:各种查表需要熟悉…

多动态调试,看看字符串被处理成什么样了

dMd-50

md5(flag) == “780438d5b6e29db0898bc4f0225935c0”

查一下就好了

Leaked_Lisence待做

file之后发现是.xz文件,ubuntu和mac都解压失败,windows里加个后缀名.xz就解压出来了……

然后再file一下,发现还是tar文件,再改后缀名解压……

好了然后我就看不懂了,好像是和导出dll有关?

wp

ReverseMe

IDA打开后发现一大堆windows相关的函数,迷失在了库函数之中

我又忘了看字符串窗口了

找到关键函数

25

ROL1是循环左移,比如0x12345678变成0x78123456

异或的key是从函数中取得的,发现每次运行都是

解密代码有点诡异,windows下用BYTE才成功输出,或者直接用unsigned char,再%c输出

之前也有char输出乱码的情况,应该是溢出的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>

int main(int argc, char**argv) {
BYTE key[] = { 26, 162, 47, 249, 148, 67, 60, 196, 77, 216, 140, 197, 91, 182, 110, 234, 163, 60, 201, 155, 188, 202, 173, 215, 126};
BYTE v9[25] = { 0x0F, 0x87, 0x62, 0x14, 0x01, 0xC6, 0xF0, 0x21, 0x30, 0x11, 0x50, 0xD0, 0x82, 0x23, 0xAE, 0x23, 0xEE, 0xA9, 0xB4, 0x52, 0x78, 0x57, 0x0C, 0x86, 0x8B };

for (int i = 0; i < 25; i++) {
BYTE temp = key[i]^v9[i];
BYTE res = (temp << 6) | (temp >> 2);
printf("%c", res);
}
return 0;
}

还有wp里的python写法,取模256

1
2
3
4
5
6
7
8
9
10
key= [26, 162, 47, 249, 148, 67, 60, 196, 77, 216, 140, 197, 91, 182, 110, 234, 163, 60, 201, 155, 188, 202, 173, 215, 126, 224]
c_txt = [0x0F, 0x87, 0x62, 0x14, 0x01, 0xC6, 0xF0, 0x21, 0x30, 0x11, 0x50, 0xD0, 0x82, 0x23, 0xAE, 0x23, 0xEE, 0xA9, 0xB4, 0x52, 0x78, 0x57, 0x0C, 0x86, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00]

s=""
for i in range(0, 25):
x = key[i] ^ c_txt[i]
y = ((x<<(8 - 2))|(x>>2))%256
print x, y
s+=chr(y)
print s

总结一下,还是查找字符串,看程序的功能交互

不要迷失在库函数之中

还有就是循环左移的解密

reverse_box

./reverse_box ${FLAG}

95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a

26

题目逻辑:fill_buffer函数中,随机取一个1-255之间的数值,根据这个数值生成一个256字节的数组

这个数组的可能性只有255种,然后就是爆破所有情况,看TWCTF在不在里面,据说和SBox有关

看了好几份wp,总之是人为设置这个种子,遍历所有情况,得到所有可能的数组

但是我学不来……….然后看TWCTF在不在输出值中

放弃了……..

crackme

exe逆向,先IDA打开发现没有main,显然是加壳了….PEID等工具查一下发现是nSPack壳,PEID自带的脱壳器还不起作用,后来看雪上找了个工具(还自带BGM…)

然后分析就很简单了,异或数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char xor_arr[16] = {
116, 104, 105, 115, 95, 105,
115, 95, 110, 111, 116, 95, 102, 108, 97, 103
};

char enc[] = {
18, 4, 8, 20, 36, 92, 74, 61, 86, 10, 16, 103, 0, 65,
0, 1, 70, 90, 68, 66, 110, 12, 68, 114, 12, 13, 64,
62, 75, 95, 2, 1, 76, 94, 91, 23, 110, 12, 22, 104,
91, 18
};

int main(int argc, char**argv) {
for (int i = 0; i < 42; i++) {
printf("%c", enc[i] ^ xor_arr[i % 16]);
}
getchar();
return 0;
}

handcrafted-pyc

wp

暂时还不想学pyc逆向,先放着吧

RE100

程序中一开始有很多pipe、fork等操作…不是很懂,不过和解题没什么关系

输入的字符串分块后,交换位置就是flag

27

28

每10个字符为一块,原本的1234共四个字符串的排列转变成为3412的排列顺序,变化排列顺序后

{daf29f59034938ae4efd53fc275d81053ed5be8c}进行比较

re3-100待做

千万不要运行这个程序,如果想体验死机的话当我没说

这个**程序,一般IDA看的复杂都交互一下吧…结果一个输入,开始满屏弹窗cmd,还在目录里面创建了几万个文件夹我艹,虚拟机卡死任务管理器都开不出来

最后继续运行虚拟机,让它继续弹窗,几秒钟后内存占用17G,最后在活动监视器里杀掉进程,向运维投诉…

不过看了wp以后发现,这题是一个pyc的exe,存了wp再说

gametime

题目比较简单,基本就是看到需要的字符时就按下回车

29

失败的话会输出FAILURE

IDA打开,搜索字符串,分析后发现只要把跳转指令改一下,这样就不用按空格了

只要让游戏自己玩就可以最后得出key了

30

有两处有FAILURE,这是其中一处,patch成jz就可以了

notsequence

杨辉三角,没什么意思,wp

exp(感谢uns3t师傅…)

xctf的wp没有排版,真难受……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import hashlib 

def yanghui_trangle(n):
def _yanghui_trangle(n, result):
if n == 1:
return [1]
else:
return [sum(i) for i in zip([0] + result, result + [0])]

pre_result = []
for i in xrange(n):
pre_result = _yanghui_trangle(i + 1, pre_result)
yield pre_result


all_lines = ""
for line in yanghui_trangle(20):
all_lines += "".join([str(c) for c in line])
print all_lines
t_md5 = hashlib.md5()
t_md5.update(all_lines)
print "RCTF{%s}"%t_md5.hexdigest()

不过官方exp出的flag也不对…….

CRACKME

夜影wp

无壳,没有main函数,看上去是MFC写的(别人说的)

字符串窗口中也没有相关显示

MessageBox的交叉引用,发现有两个函数调用了它

看汇编时发现这两个函数的call都是来源于同一个函数,并且还是分支关系

34

在IDA中按P,再F5

35

回到汇编状态找到sub_401720和sub_4016e0的地址,在OD中下断,再点击注册按钮果然被401720断下来了,说明这里就是关键跳

if的判断中是关键的flag_check

36

初始以10作为种子,rand[0]为0x47(71);以1作为种子,rand[0]为0x29(41)
也就是说seed代入数组运算时恒为1

MFC的updateData可以理解为读入字符串

因为这里是指针调用函数,if的条件又太乱了,直接看汇编

37

看出要求输出的字符串长度为0x21,然后进行检查(再回去看看F5的结果也能得到)

这种直接把输入进去比较,当然是直接动态调了

38

可以直接断几十次记录下应有的输入,第一个是0x68也就是f

39

不过这里既然已经分析出逻辑了

v3[v5 + 96 + seed] // (v3+97)[10x]

找到这个字符串,IDA里提取一下

输出第(10n+1)个字符就可以了

flag{The-Y3ll0w-turb4ns-Upri$ing}

有一点问题就是……没看出来为什么a2就是我们的输入

最后的一些思考:

又学习到了srand、rand的一个特性,通过初始种子,随机出的第一个数经过一定运算再作为种子,输出随机数,以此往复,最后输出的值可以是固定的

还有就是一长串字符串,跳着比较输出,可以一定的混淆

MFC程序的一些特征,API等

Shuffle

题目描述:找到字符串在随机化之前

好的,结果一找就找到了,送分题

高手进阶

Newbie_calculations

程序会自己跑出flag,主要是代码中用了故意耗时的计算函数

都是加减乘,分析一下不难看出,网上找了一个改好函数名的代码

每一位字符都是独立的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// all flag chars are set to 1
for ( i = 0; i < 32; ++i )
flag_chars[i] = 1;

flag_chars[32] = 0; // null terminator

print_text("Your flag is:");

var0 = mul_ab(flag_chars, 1000000000);
var1 = sub_ab(var0, 999999950);
mul_ab(var1, 2);
// 100 = d

var2 = add_ab(&flag_chars[1], 5000000);
var3 = sub_ab(var2, 6666666);
var4 = add_ab(var3, 1666666);
var5 = add_ab(var4, 45);
var6 = mul_ab(var5, 2);
add_ab(var6, 5);
// 97 = a

var7 = mul_ab(&flag_chars[2], 1000000000);
var8 = sub_ab(var7, 999999950);
var9 = mul_ab(var8, 2);
add_ab(var9, 2);
// 102 = f

var10 = add_ab(&flag_chars[3], 55);
var11 = sub_ab(var10, 3);
var12 = add_ab(var11, 4);
sub_ab(var12, 1);
// 56 = 8

var13 = mul_ab(&flag_chars[4], 100000000);
var14 = sub_ab(var13, 99999950);
var15 = mul_ab(var14, 2);
add_ab(var15, 2);
// 102 = f

var16 = sub_ab(&flag_chars[5], 1);
var17 = mul_ab(var16, 1000000000);
var18 = add_ab(var17, 55);
sub_ab(var18, 3);
// 52 = 4

var19 = mul_ab(&flag_chars[6], 1000000);
var20 = sub_ab(var19, 999975);
mul_ab(var20, 4);
// 100 = d

var21 = add_ab(&flag_chars[7], 55);
var22 = sub_ab(var21, 33);
var23 = add_ab(var22, 44);
sub_ab(var23, 11);
// 56 = 8

var24 = mul_ab(&flag_chars[8], 10);
var25 = sub_ab(var24, 5);
var26 = mul_ab(var25, 8);
add_ab(var26, 9);
// 49 = 1

var27 = add_ab(&flag_chars[9], 0);
var28 = sub_ab(var27, 0);
var29 = add_ab(var28, 11);
var30 = sub_ab(var29, 11);
add_ab(var30, 53);
// 54 = 6

var31 = add_ab(&flag_chars[10], 49);
var32 = sub_ab(var31, 2);
var33 = add_ab(var32, 4);
sub_ab(var33, 2);
// 50 = 2

var34 = mul_ab(&flag_chars[11], 1000000);
var35 = sub_ab(var34, 999999);
var36 = mul_ab(var35, 4);
add_ab(var36, 50);
// 54 = 6

var37 = add_ab(&flag_chars[12], 1);
var38 = add_ab(var37, 1);
var39 = add_ab(var38, 1);
var40 = add_ab(var39, 1);
var41 = add_ab(var40, 1);
var42 = add_ab(var41, 1);
var43 = add_ab(var42, 10);
add_ab(var43, 32);
// 49 = 1

var44 = mul_ab(&flag_chars[13], 10);
var45 = sub_ab(var44, 5);
var46 = mul_ab(var45, 8);
var47 = add_ab(var46, 9);
add_ab(var47, 48);
// 97 = a

var48 = sub_ab(&flag_chars[14], 1);
var49 = mul_ab(var48, 4000000000);
var50 = add_ab(var49, 55);
sub_ab(var50, 3);
// 52 = 4

var51 = add_ab(&flag_chars[15], 1);
var52 = add_ab(var51, 2);
var53 = add_ab(var52, 3);
var54 = add_ab(var53, 4);
var55 = add_ab(var54, 5);
var56 = add_ab(var55, 6);
var57 = add_ab(var56, 7);
add_ab(var57, 20);
// 49 = 1

var58 = mul_ab(&flag_chars[16], 10);
var59 = sub_ab(var58, 5);
var60 = mul_ab(var59, 8);
var61 = add_ab(var60, 9);
add_ab(var61, 48);
// 97 = a

var62 = add_ab(&flag_chars[17], 7);
var63 = add_ab(var62, 6);
var64 = add_ab(var63, 5);
var65 = add_ab(var64, 4);
var66 = add_ab(var65, 3);
var67 = add_ab(var66, 2);
var68 = add_ab(var67, 1);
add_ab(var68, 20);
// 49 = 1

var69 = add_ab(&flag_chars[18], 7);
var70 = add_ab(var69, 2);
var71 = add_ab(var70, 4);
var72 = add_ab(var71, 3);
var73 = add_ab(var72, 6);
var74 = add_ab(var73, 5);
var75 = add_ab(var74, 1);
add_ab(var75, 20);
// 49 = 1

var76 = mul_ab(&flag_chars[19], 1000000);
var77 = sub_ab(var76, 999999);
var78 = mul_ab(var77, 4);
var79 = add_ab(var78, 50);
sub_ab(var79, 1);
// 53 = 5

var80 = sub_ab(&flag_chars[20], 1);
var81 = mul_ab(var80, -294967296);
var82 = add_ab(var81, 49);
sub_ab(var82, 1);
// 48 = 0

var83 = sub_ab(&flag_chars[21], 1);
var84 = mul_ab(var83, 1000000000);
var85 = add_ab(var84, 54);
var86 = sub_ab(var85, 1);
var87 = add_ab(var86, 1000000000);
sub_ab(var87, 1000000000);
// 53 = 5

var88 = add_ab(&flag_chars[22], 49);
var89 = sub_ab(var88, 1);
var90 = add_ab(var89, 2);
sub_ab(var90, 1);
// 50 = 2

var91 = mul_ab(&flag_chars[23], 10);
var92 = sub_ab(var91, 5);
var93 = mul_ab(var92, 8);
var94 = add_ab(var93, 9);
add_ab(var94, 48);
// 97 = a

var95 = add_ab(&flag_chars[24], 1);
var96 = add_ab(var95, 3);
var97 = add_ab(var96, 3);
var98 = add_ab(var97, 3);
var99 = add_ab(var98, 6);
var100 = add_ab(var99, 6);
var101 = add_ab(var100, 6);
add_ab(var101, 20);
// 49 = 1

var102 = add_ab(&flag_chars[25], 55);
var103 = sub_ab(var102, 33);
var104 = add_ab(var103, 44);
var105 = sub_ab(var104, 11);
add_ab(var105, 42);
// 98 = b

add_ab(&flag_chars[26], flag_chars[25]); // flag_chars[25] = 98
// 99 = c

add_ab(&flag_chars[27], flag_chars[12]); // flag_chars[12] = 49
// 50 = 2

var106 = flag_chars[27]; // 50
var107 = sub_ab(&flag_chars[28], 1);
var108 = add_ab(var107, var106);
sub_ab(var108, 1);
// 49 = 1

var109 = flag_chars[23]; // 97
var110 = sub_ab(&flag_chars[29], 1);
var111 = mul_ab(var110, 1000000);
add_ab(var111, var109);
// 97 = a

var112 = flag_chars[27]; // 50
var113 = add_ab(&flag_chars[30], 1);
mul_ab(var113, var112);
// 100 = d

add_ab(&flag_chars[31], flag_chars[30]); // flag_chars[30] = 100
// 101 = e

print_func("CTF{");

for ( j = 0; j < 32; ++j )
print_func("%c"); // print flag

print_func("}\n");

最后的flag CTF{daf8f4d816261a41a115052a1bc21ade}

actually_cpp.swf待做

swf文件,再说

internet-of-what

TMD也太难了吧,放弃放弃,和固件什么有关

wp

myDriver待做

驱动逆向,wp上和hook无关,直接逆的算法,存了pdf

一个简单的Inlinehook,hook NtCreateFile 函数。

在任意路径打开文件名为 P_giveMe_flag_233.txt 的文件超过8次,在第9次打开 P_giveMe_flag_233.txt 的时候就会在里面写入flag。 文件名进过简单的加密,加密的 key 是自己构造的一段 win64 的汇编生成

另外的wp,等学了hook再看看

还是得看看《加密与解密》

家徒四壁-void

hitcon2017的题….elf注入

对不起,看不懂

wp

攻防世界的wp比较详细,但是我看不懂

debg.exe

没打错,题目就是叫debg

又是一个.net逆向,发现做过的几题都是下断点然后就明文比较出flag了…..

不过这题需要用32位的dnSpy

31

吐槽一句,这个平台上的难度评级就是闹着玩的…

HW-RE

18年国赛的一题

通过strtok切割flag,flag类似于CISCN{flag1_flag2_flag3}

32

第二、三段存入变量显示是循环+数组方式,实际上是后文会直接用到的一个变量,观察栈布局偏移可以看出来

后面就是把这三段flag分别检查了

33

第一个检查我感觉各种wp不太严谨

前面一大段是一个md5,不过一开始不太好猜,后面是根据加密过的hash值反推出原本的hash值再去查找

wp说:明文hash中的A-F字符,经过运算后可以生成大于F的字符,这样就可以反推出原来hash里的字符

问题:比如字符K,可能是由A-F经过运算得出的,也可能本身就是K

(没有仔细分析,也有可能前面限制了明文hash中英文字母都是A-F)

不管了,跳过这一步,就认为原来明文hash英文字母都是A-F

1
2
3
4
5
6
7
8
9
def check1(str0):
flagmd5 = ''
for i in range(len(str0)):
temp = ord(str0[i])-i%10
if temp <= ord('A') + 5 and temp >= ord('A'):
flagmd5 += chr(temp)
else:
flagmd5 += str0[i]
return flagmd5

解密后结果:yubu

第二个检查:

明文hash异或一组数据后,再经过前面检查的同样的运算,得到一个hash

解密:先同样用上面的方法,再异或,最后查询md5,得到kulo

第三个检查,感觉没什么意思(不太喜欢图片那些),贴wp了

flag3和flag2的算法一样,只是flag3长度为16位,很难破解查询,但随后提供了一个方法可以获取到flag3。如下:

1)取flag2的哈希(16进制)的16字节之和(记为total),然后使用total产生两个值。 x1 = total/16 x2 = total%16

2)将x1和x2分别和flag3的第4、5位进行异或得到xor1和xor2,即

1
2
xor1 = x1^flag3[3]
xor2 = x1^flag3[4])

3)全局变量中预置了一段数据data,将上面的xor1和xor2分别和data的奇偶字节进行异或得到数据data1,使用fwrite写入文件

4)只要输入的flag3[3]、 flag3[4]合适,就会产生一张图片,里面记录了完整的flag3。

5)所以需要通过写文件这个操作能联想到写入的文件是图片文件,然后根据图片文件的头部固定字节就可以反推出flag3[3]、 flag3[4]

6)本来开始是在写文件的时候加上后缀,这样就可以降低题目难度,后面想了下还是先不加后缀,可以将这个后缀放到提示里面。

另外一个wp提到,2个char数据可以爆破,因为出题人给了一张png,所以可以查找图片头尾字段

wp2

题目做到这里,感觉md5、hash的那些还是需要一些直觉

看到一堆函数,一段类似(加密过的)hash,应该先解密原先的hash,而不是直接拿头逆函数

还有就是代码里有一段malloc没看懂,也许是混淆?感觉没什么用

uwp-454

uwp逆向,再见

catalyst

做过的题,主要的一点就是随机种子确定,随机序列也确定

wp

unvm_me.pyc待做

wps

shamecontrol-200待做

SE壳脱壳,.net

存了wp

TankGame

题目给了一个rar文件,解压后发现有游戏exe,一些地图之类,通关给flag

看了网上的wp,有的是用IDA把敌方数量降成1,有的是改地图

而我就比较厉害了,我连游戏都打不开,再见

what-does-this-button-do

jar文件,看到FlagActivity()

1
2
3
4
5
6
7
8
for (;;){
if (i >= 22){
((TextView)findViewById(2131230721)).setText(paramBundle);
return;
}
paramBundle = paramBundle.concat(String.valueOf((char)new int[] { 102, 108, 97, 103, 123, 119, 52, 110, 110, 52, 95, 106, 52, 114, 95, 109, 121, 95, 100, 51, 120, 125 }[i]));
i += 1;
}

直接转成ASCII,flag{w4nn4_j4r_my_d3x}

Sharif_app

反编译之后

40

看到关键逻辑是isCorrect函数,还提到了Native

41

apk中输入正确即输出flag,可以直接跟算法,但是我看不懂这些API

于是找到生成libadnjni.so,IDA中看到其实是一个strcmp,变量获取下来转成字符串即可

应该就是反编译看不出来函数体的就去lib里找吧…

libdroid

看起来比较麻烦,不做了…

hi-200待做

程序被VMP保护,会输出windows系统一些参数,如果参数都与要求的相同则输出flag

需要了解windowsAPI,动态调试,但是实际上手可能比较难…