攻防世界题目练习——Reverse新手+引导模式(持续更新)

1. 666

下载附件
用IDA Pro打开文件,直接看到main入口,反编译查看代码如下:
注:strcmp(a,b)函数当a=b时返回值为0。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[240]; // [rsp+0h] [rbp-1E0h] BYREF
  char v5[240]; // [rsp+F0h] [rbp-F0h] BYREF

  memset(s, 0, 0x1EuLL);
  printf("Please Input Key: ");
  __isoc99_scanf("%s", v5);
  encode(v5, (__int64)s);
  if ( strlen(v5) == key )
  {
    if ( !strcmp(s, enflag) )
      puts("You are Right");
    else
      puts("flag{This_1s_f4cker_flag}");
  }
  return 0;
}

可以看到,输入的“Key”作为v5字符串传入encode()函数中,然后将v5的长度与key比较,再比较字符串senflag,查看key和enflag的值:
在这里插入图片描述
我们点击进入函数encode()查看函数内容如下:

int __fastcall encode(const char *a1, __int64 a2)
{
  char v3[104]; // [rsp+10h] [rbp-70h]
  int v4; // [rsp+78h] [rbp-8h]
  int i; // [rsp+7Ch] [rbp-4h]

  i = 0;
  v4 = 0;
  if ( strlen(a1) != key )
    return puts("Your Length is Wrong");
  for ( i = 0; i < key; i += 3 )
  {
    v3[i + 64] = key ^ (a1[i] + 6);
    v3[i + 33] = (a1[i + 1] - 6) ^ key;
    v3[i + 2] = a1[i + 2] ^ 6 ^ key;
    *(_BYTE *)(a2 + i) = v3[i + 64];
    *(_BYTE *)(a2 + i + 1LL) = v3[i + 33];
    *(_BYTE *)(a2 + i + 2LL) = v3[i + 2];
  }
  return a2;
}

可以看到第一段代码中的调用encode(v5,s),v5,s相当于下面encode函数代码中的a1,a2。
可以看到首先比较字符串a1的长度是否==key,然后将a1的每3个字节的值为一组,分别+ - ^6,并和key进行异或操作,再将值赋值给a2对应位置的3个字节,最后返回a2的值。
因此encode(v5,s)就是将v5的值进行加密操作后得到s。
然后将s的值与enflag的值比较,相等即可。
因此我们写一个反向解密的脚本,将原来的加密操作反过来执行:

python:

#python脚本在将字符和整型进行操作时,没有办法直接转换,要自己进行字符类型转换
#s=enflag="izwhroz\"\"w\"v.K\".Ni"
s = ''
enflag = 'izwhroz""w"v.K".Ni'
key = 18
# 12h=16*1+2=18
for i in range(0, key, 3):
    s += chr((ord(enflag[i]) ^ key) - 6)
    s += chr((ord(enflag[i + 1]) ^ key) + 6)
    s += chr((ord(enflag[i + 2]) ^ key) ^ 6)

print(s)
#unctf{b66_6b6_66b}

C:

#include <stdio.h>

int main(){
    char s[20]={ };
    char enflag[]= "izwhroz\"\"w\"v.K\".Ni";
    int key=18;

    for(int i=0;i<key;i+=3){
        s[i] = (enflag[i] ^ key) - 6;
        s[i + 1] = (enflag[i + 1] ^ key) + 6;
        s[i + 2] = (enflag[i + 2] ^ key) ^ 6;
    }

    printf("%s",s);
}
//unctf{b66_6b6_66b}

2.Reversing-x64Elf-100

下载附件
找到入口函数main:
可以看到对输入的password用一个函数进行了操作:
在这里插入图片描述
我们进入这个函数查看,可以看到,需要函数返回0,即如下条件成立:

*(char *)(v3[i % 3] + 2 * (i / 3)) - *(char *)(i + a1) == 1

在这里插入图片描述
也就是 (a1+i)=(v3[i%3]+2*(i/3))-1
故脚本如下:

v = ["Dufhbmf", "pG`imos", "ewUglpt"]
a = ""
for i in range(12):
    a += chr(ord(v[i % 3][2 * (i // 3)]) - 1)

print(a)
#输出:
#Code_Talkers

真的是被报错折磨半天,一直报错各种类型之类的问题,一开始一直以为是把v3[0]这种整个字符串变成int类型的值然后加上2*(i/3),后来看了解析终于发现,(char *)(v3[i % 3] + 2 * (i / 3)),v3[i%3]只是一个地址,后面加上2*(i/3)是将指针后移,前面有个char*指针,也就是说v3[i % 3] + 2 * (i / 3)是个地址。
可恶,太久没接触写代码,一直接触python脚本,已经忘了C语言了。

3. easyRE1

在这里插入图片描述
直接出现flag,给字符串加上flag{}。

4. insanity

在这里插入图片描述
进入查看strs数组:
在这里插入图片描述

5. open-source

源代码如下:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 4) {
    	printf("what?\n");
    	exit(1);
    }
//需要4个参数,其中第一个参数为文件名
    unsigned int first = atoi(argv[1]);
    if (first != 0xcafe) {
    	printf("you are wrong, sorry.\n");
    	exit(2);
    }
//第二个参数为0xcafe转整型51966
    unsigned int second = atoi(argv[2]);
    if (second % 5 == 3 || second % 17 != 8) {
    	printf("ha, you won't get it!\n");
    	exit(3);
    }
//要求argv[2]%17==8且argv[2]%5!=3,则argv[2]取25
    if (strcmp("h4cky0u", argv[3])) {
    	printf("so close, dude!\n");
    	exit(4);
    }
//要求argv[3]="h4cky0u"
    printf("Brr wrrr grr\n");

    unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;
//计算hash=51966*31337+8*11+7-1615810207=12648430
    printf("Get your key: ");
    printf("%x\n", hash);
//转成16进制:c0ffee
    return 0;
}

6. game

题目:
在这里插入图片描述
就和原神解谜一样让8行全部亮起来就行,本人就当作游戏纯手工试出来的(乖巧.jpg)
在这里插入图片描述
也可以IDA打开后改源码:
在这里插入图片描述
将判断条件后面5个都改成!=1,然后在控制台输入2,就可以获得flag。

7. Hello, CTF

main函数如下:
在这里插入图片描述
如图,首先将字符串"437261636b4d654a757374466f7246756e"复制给v13,接下来v10被初始化为0。输入的内容作为v9,判断v9的长度>0x11则结束循环退出,因此要求输入内容长度<=0x11,也就是<=17。
然后接下来的for循环将v9的值赋值给v4,遇到空字符则退出,然后将v4的值以16进制形式写入Buffer中,再将Buffer接到v10后面,而由于v10初始化为全0,故V10的内容就是Buffer的内容。
随即比较v10与v13的值,相等则输出"Success"。也就是需要v10=“437261636b4d654a757374466f7246756e”,可以进行ASCII码转换得到flag:“CrackMeJustForFun”

8. re1

先打开文件逆向查看,前面有很多printf语句不知道打印了什么,最后的if语句输出两个字符串,不知道哪一个才是成功获得flag的反馈,于是直接运行exe程序查看如下:
在这里插入图片描述
因此猜测if语句的v3!=0时是flag错误的提示,也就是v3=0时,v7==v5.m128i_i8时获得flag,因此需要知道v5.m128i_i8的内容。
在这里插入图片描述
查看v5的结构如下:
_m128i是一个union联合类型,再看上面源码中,v5是将xmmword_413E34转换为_m128i类型的结构,因此我们取xmmword_413E34即为flag。
在这里插入图片描述
看到xmmword_413E34内容如下,数据类型为16进制,因此对其进行ASCII码转换得到flag。
要注意字节是从低到高位,转成ASCII码的排列顺序应为:
4455544354467B57653163306D657430
4455544354467D
在这里插入图片描述
一直以为源码中比较字符串时v5.m128i_i8只有16字节所以只比较16字节,没想到后面qword_413E44和前面xmmword是跟在后面一起的QAQ。没搞懂,还是说v5.m128i_i8只是一个地址,后面字符串全都算是一整个字符串。
看了别人的博客知道还可以用快捷键A或者右键把这串16进制直接转换成ASCII码:
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值