BUU CTF REVERSE-文字WP

reverse 1

在下载后得到相应的程序,拖入到DIE中,检测到程序是没有加壳的

然后拖入IDA x64中,在View-A界面,查看有没有字符串,简单的提供一些信息

查看字符串 1、直接看 2、shift+F12

定位到一句 'this is the right flag'

然后ctrl+x(交叉引用)查看是哪段函数调用了该字符串,点击OK,查看其汇编代码。

然后F5查看伪c代码

首先定位到比较语句,发现如果str1 == str2,则正确
strncmp(str1,str2,v3)是把str1与str2两字符串的前v3位数做一个比较,若str1=str2,返回0;大于返回正数,小于返回负数

sub_1400111D1是print函数,相应的sub_14001128F是scanf函数

锁定Str2 = {hello_world}

将程序向上分析,发现了一段比较替换的,赋值为ASCII 111,选中字符按R后,将数字转为字符,发现是将o替换成0

所以flag{hell0_w0rld}

reverse2

下载文件后,发现文件并不是exe文件,但是拖入DIE中确发现是一个64位的文件

然后拖入IDA后,发现this is right flag字样

F5进入伪码后,发现和上一题类似,就是替换比较

然后寻找文中的flag

发现flag{hacking_for_fun},将r和i替换成1后,就是最终的flag

新年快乐

首先下载下来附件后,检测后发现是PE32位程序,然后根据wp显示有UPX加壳

脱壳后,拖入IDA,然后锁定true flag,查看伪码后,发现了语句

审计代码后,发现了flag

XOR

根据题目XOR,发现题目应该与异或有关

拖入DIE后,发现是mac文件,然后才有IDAx64打开后

首先发现INPUT YOUR FLAG

然后F5编译出伪代码后,进行代码审计

发现首先flag长度应该为33位

然后将第i位和i-1位进行异或,然后与glabal进行比较
其中shift+e调出数组中的字符,调整为c无符号数组(十进制)

编写脚本,再次进行异或,就可以得到flag,两次异或后还原,一致后输出
注意glabal参数,定位后,向上找,先确定参数类型,然后从界面的左侧可以看出来,然后再次确定参数

flag{QianQiuWanDai_YiTongJiangHu}

helloword

下载下来文件后,发现是apk结尾,是Android文件,然后拖入AndrodiIDE

在smali-com-example-helloword中第二个文件中发现了flag

reverse_3

打开文件后,发现是PE32,加载后,发现input flag

查找到最后,存在比较,一致后为flag

str2 e3nifIH9b_C@n@dH

先将其for循环解除,e2lfbDB2ZV95b3V9

观察这个,发现也不像是flag,然后发现上面还有一个函数,点进去后,有一个数组,限定是64,点进去发现是大小写英文字母以及+/=,猜测应该是某种编码

不一样的flag

下载下来附件后,检测到是PE32的文件,然后通过IDA编译后,发现一串字符,感觉flag应该和这个有关系

然后向下阅读伪代码,发现输入1、2、3、4后,赋值,判断,然后v3和v4加减

落到最后,发现如果是1,则退出,如果是#则最后输出

根据wp中发现。属于迷宫题
*1111
01000
01010
00010
1111#

从*出发,到#  需要输入22244114422
那么flag就是刚刚的数字
https://blog.csdn.net/qq_66455531/article/details/129645357

simpleRev

下载后得到一个elf文件,DIE后发现是一个64位的,放入IDAx64中

编译成伪代码后,第一遍没有看到flag,函数也很简单

第二遍再看的时候,发现Decry()

点进去看,发现最后的Congratulation!

沿着代码,向上看,有比较,猜测和text比较的str2应该就是flag

然后分别找到
key = killshadow
key = ADSFK
src = SLCDN
key = ADSFKNDCLS

这里有一个知识点,就是计算机中更倾向于小端排序,即将多位数的低位放在较小的地址处,,高位放在较大的地址处。与人的阅读习惯相反,那么SLCND 按照人们的阅读习惯就是DNCLS

然后接下来就是将字符串,从大写转为小写

key = adsfkndcls

根据伪代码的语句,前两句判断,根据text字符串,我认为是不需要进行逆向的,然后在往下,分别看到了
if ( v1 <= '`' || v1 > 'z' )
  {
    if ( v1 > '@' && v1 <= 'Z' )
结合ASCII码表判断,就是要求输入字符是大写字母或者小写字母

在经过
	str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
进行转换

   因为代码能力的问题,只能选择爆破

   猜测应该是输入大写的字符,然后转,先用大写的字母爆破是因为+97,如果0+97,正好是a

   最后,脚本
   text = 'killshadow'
	key = 'adsfkndcls'
	burte = 'QWERTYUIOPASDFGHJKLZXCVBNM'

v3 = 0
v5 = len(key)
flag = ''

for j in text:
    for i in range(len(burte)):
        v1 = (ord(burte[i]) - 39 - ord(key[v3 % v5]) + 97) % 26 +97
        if ord(j) == v1:
            flag += burte[i]
    v3 += 1

输出KLDQCUDFZO后,加上flag{},flag正确

print(flag)

Java逆向解密

采用jd-gui打开后,发现了代码

和PE文件一样,最后都是比较,然后一致后输出

通过代码,发现有几句整型转换的语句,没有作用,扔掉

int[] KEY = { 
    180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 
    133, 191, 134, 140, 129, 135, 191, 65 };

KEY就是最后比较的

核心加密就是这一条
for (int i = 0; i < arr.length; i++) {
  int result = arr[i] + 64 ^ 0x20;
} 

逆向代码
keyList = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
    133, 191, 134, 140, 129, 135, 191, 65 ]

flag = ''
for i in keyList:
    result = (i - 64) ^ 32
    flag += chr(result)

print(flag)

luck_guy

首先现在,解析后是64位程序,然后采用IDA 64打开

从字符串进入,不断确定函数,然后锁定到
strcat((char *)&s, f1);          // f1 = GXY{do_not_
strcat((char *)&s, &f2);

但是f2没有办法确定,
但在接下来的case中发现了

s = 0x7F666F6067756369LL;
v5 = 0;
strcat(&f2, (const char *)&s);

for ( j = 0; j <= 7; ++j )
{
      if ( j % 2 == 1 )
        *(&f2 + j) -= 2;
      else
        --*(&f2 + j);
}

&f2 + j就是用循环次数来控制地址的移动,但是也只是在本次循环时移动到这,并没有改变初始地址。

然后根据上面s = .....中的十六进制也就是它的地址

将地址以两位为一组,区分开,然后生成新的列表,根据上面的内容编写脚本

获得GXY{do_not_hate_me}

#reverse-luck_guy
flag = 'GXY{do_not_'
#因为计算机中多是小端序,所以
str = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1]

for i in range(len(str)):
    if (i % 2 == 1):
        #这个位置转不转为10进制的都是可以的,减去时候,要不以十进制转换为字符,要不以十六进制转换为字符
        cha = chr(str[i] - 2)
    else:
        cha = chr(str[i] - 1)
    flag += cha
print(flag)

[BJDCTF2020]JustRE

首先die分析为32位程序,然后点进去后发现没有找到与flag相关的信息

这时shift+F12,找出程序中的字符串,找到了
.data:00407030	0000001B	C	 BJD{%d%d2069a45792d233ac}
.data:0040704C	00000010	C	您已经点了 %d 次

这个应该与flag有关

点进去后ctrl+x,交叉追踪后,F5编译伪代码,然后发现相关代码。

if ( dword_4099F0 == 19999 )
{
    sprintf(String, " BJD{%d%d2069a45792d233ac}", 19999, 0);
    SetWindowTextA(hWnd, String);
    return 0;
}

这出代码应该是点击19999次后,弹出,%d%d应该就是19999和0

刮开有奖

首先根据题目,没有找到相关的内容,然后shift+F12,寻找所有的字符串,发现了一个字符串有些像,ctrl+x寻找交叉的内容,然后F5。进行编译,在伪代码中,发现string是一个被比对字符串
最后应该是求出该字符串

// string长度应该是8
{
  v7[0] = 'Z';                              // v7 = 90 = Z
  v7[1] = 'J';                              // v71 = 74 = J
  v8 = 'S';                                 // v8 = 83 = S
  v9 = 'E';                                 // v9 = 69 = E
  v10 = 'C';                                // v10 = 67 = C
  v11 = 'a';                                // v11 = 97 = a
  v12 = 'N';                                // v12 = 78 = N
  v13 = 'H';                                // v3 = 72 = H
  v14 = '3';                                // v14 = 51 = 3
  v15 = 'n';                                // v15 = 110 = n
  v16 = 'g';                                // v16 = 103 = g
  sub_4010F0(v7, 0, 10);                    // 3CEHJNSZagn

  sub_4010F0转为C代码,运行后,得到3CEHJNSZagn

  根据这串代码,可以知道string0-7是哪个字符,v7就已经是3CEHJNSZagn
  程序中的有的是地址相加。
  if ( String[0] == v7[0] + 34              // string0 U
    && String[1] == v10                     // v10 =J string1
    && 4 * String[2] - 141 == 3 * v8        // string2 = W
    && String[3] / 4 == 2 * (v13 / 9)       // string 3 =P
    && !strcmp(v4, "ak1w")                  // V4 = jMp == V18 012
    && !strcmp(                             // V5 WP1 V18 012
          v5,
          "V1Ax") )

    v4、v5是base64的加密程序,根据上面的比较语句,应该是加密后与其相同则原字符应该是解密的
    v4 = sub_401000(v18, strlen(v18));
    v5 = sub_401000(v18, strlen(v18));

    最后解出  STRING = UJWP1jMp

简单注册器

下载下来附件后,得到一个apk结尾的文件,属于安卓的,然后拖入jdax中在mainactivity中发现了flag

然后根据判断的语句,以及最后的return
if (flag == 1) {
                char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
                x[2] = (char) ((x[2] + x[3]) - 50);
                x[4] = (char) ((x[2] + x[5]) - 48);
                x[30] = (char) ((x[31] + x[9]) - 48);
                x[14] = (char) ((x[27] + x[28]) - 97);
                for (int i = 0; i < 16; i++) {
                    char a = x[31 - i];
                    x[31 - i] = x[i];
                    x[i] = a;
                }
                String bbb = String.valueOf(x);
                textview.setText("flag{" + bbb + "}");
                return;

改写为python,输出得到flag
flag{59acc538825054c7de4b26440c0999dd}

pyre

下载下来的文件,是pyc,需要反编译

借助网站或者
pip install uncompyle6
uncompyle6 -o attachment.py attachment.pyc

反编译后
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 2.7

print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
	num = ((input1[i] + i) % 128 + 128) % 128进行操作


	code += num

for i in range(l - 1):
	code[i] = code[i] ^ code[i + 1]

print code
code = [
	'%1f',
	'%12',
    '%1d',
    '(',
    '0',
    '4',
    '%01',
    '%06',
    '%14',
    '4',
    ',',
    '%1b',
    'U',
    '?',
    'o',
    '6',
    '*',
    ':',
    '%01',
    'D',
    ';',
    '%',
    '%13']

则应该先对其进行异或预算,然后对num = ((input1[i] + i) % 128 + 128) % 128进行操作

((input1[i] + i) % 128 + 128) % 128
数学逻辑分析:
	令(input1[i] + i)为X,
	假设X > 128,对128取模后,得余数,余数在加128,在对128取余,还是得余数
	假设X < 128,对128取模后得起本身, 那么余数在加128,对128取余,还是其本身
现在已知code列表,也就是各个num的值,也就是(input1[i] + i) % 128的结果。同时我也知道每个num所对应的i,一个未知数一个方程,input1[i]首先可以确定是可求的。

根据我上面假定数值的运算过程,很容易发现我想求input1[i]+5,只需要求n*128+3即可。那么n是多少呢?首先我的input1范围是0-127,i的范围是0-22,那么input1[i]+i显然小于150,也就是不可能超过128*2,那么n最大只能是1才能保证n*128+num小于150 。

所以input1[i]=128+num-i。但是这里又出现一个问题,也就是说,如果我的128+num-i大于128怎么办呢?我的flag是0-127的数值呀。所以我需要对它再进行一次取模:

则逆向代码为
	ord(code[i])-i)%128


又或者
	(a+b)%c=(a%c+b%c)%c、A=(B-C)%D,那么B=(A+C)%D,直接推出逆向代码

[ACTF新生赛2020]easyre

在IDA中查看后,发现逻辑很清晰,只有对V5进行了调取,然后与V4进行比较,那么V5就是我们要找到的flag,并且代码的最开始的比较字符内容,正好是ACT{},那么V5中的内容应该是{}中的内容,将V4中的字符转换为十进制的ASCII,然后在data_str中寻找索引位置,data_str要找全,然后确定下来索引位置+1,就是V5中字符的ASCII,代码如下:
	data_start = ('~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJ'
	              'IHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$# !"')
	encrypt = [42,70,39,34,78,44,34,40,73,63,43,64]
	
	flag = ''
	for i in encrypt:
	    flag += chr(data_start.find(chr(i))+1)
	'''
	逆向想法
	v4[i] = data_start(*((char *)v5+i)-1)
	明确索引
	v4[i]-转为了字符串中的ASCII,然后明确char * v5加的i就代表着flag的第几位
	*()会获取相应的ASCII值  -1后,为索引
	
	那么v4[i]的字符确定在data_str中相应字符的索引
	索引就是*((char *)v5+i)-1的结果,然后加+1取字符就是flag的某位字符的ASCII
	在转为字符就是flag
	'''
	print(flag)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值