SWPU NSS 2022 秋季招新赛 Reverse 出题人笔记

贪吃蛇

出题人:Dkymore

这道题其实是希望大家能用ctf的方式做出来

而不是玩上60分

CE方法

可以使用 CE 修改分数 但是你会发现修改分数没有用

思考一下 或是用ida查看 gameMainLoop

IDA sprintf_s(Buffer, 0x20u, "title score:%d", v18 - 4);

源代码 sprintf_s(deaw, 32, "title score:%d", len - 4);

因为游戏其实没有用一个单独的变量表示score

而是用蛇身长度-初始蛇身长度 表示分数

使用ce直接修改蛇身长度即可

ctf方法

直接找到密文和解密函数 就是一个普通的异或

程序源代码

密码:1234

babyre

出题人:Dkymore

打开就能看见

如果你直接双击 程序会闪一下

这是因为程序在显示完后就退出了

你可以在cmd中打开程序 这样就不存在上面的问题了

easyre

出题人:Dkymore

使用IDA打开程序即可看见flag

scanf("%d", &ip);
if(ip==114514){
   printf("NSSCTF{oh_you_find_it}");
}

可以看见 这里要去输入114514即可得到flag

不过直接用IDA即可得到flag

这里其实也体现了ctf这种flag形式在逆向上的一些特点

xor

出题人:Dkymore

for(int i=0; i<39; i++){
   if((flag[i] ^ 2) != encrypted_flag[i]){
       printf("\nwrong flag");
       return 0;
  }
}

printf("\nflag is right");

IDA 打开程序 我们可以看见 输入的flag和2异或后要求等于密文

编写python脚本 或者手算都可以 (windows的计算器,在线网页) 都可以

def xxx(x,e=2):
   return "".join([chr(ord(i)^e) for i in x])
print(xxx(密文))

UPX

出题人:Dkymore

题目本身和xor一样 区别只是加上了UPX壳

使用查壳工具 比如 die 即可发现是 UPX壳

(题目名称和题目内容都有提示)

使用 upx -d 文件 即可还原文件 其他和xor一样就不再赘述

base64

出题人:susuqiong

题目给足了提示,base64,下载附件是一个二进制文件,拖入ida查看。找到加密字符串。

image-20221024103904939

解密得到flag:NSSCTF{base_64_NTWQ4ZGDNC7N}

base64-2

出题人:susuqiong

同样是base64,我们可以发现ida打开文件,其中base64的码表发现了变化。找到码表及密文:

import base64
# from hexdump import hexdump
# Base64
_t1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
_t2 = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm0123456789+/"
flag = "GyAGD1ETr3AcGKNkZ19PLKAyAwEsAIELHx1nFSH2IwyGsD=="
flag = base64.b64decode(flag.translate(str.maketrans(_t1, _t2)))
print(flag)

得到flag:NSSCTF{siMp13_Base64_5TXRMZHU6V9S}

py1

出题人:P1tie5

这个题有两种方法解出来: 第一种: 既然是exe文件就试着运行看看:

image-20221023110926435

第一个问题比较简单,关于异或的计算可以去百度看看,这里就不细讲当然,会一点python就可以很快算出来

image-20221023110955759

或者用计算器也可以

那第一个问题的答案就是 970

image-20221023111411209

接下来第二个问题,就是和异或的性质有关系了,这个问题我们可以引用上一个题的答案和问题来解释: 我们知道2684 XOR 2486 = 970 那试试2684 XOR 970 = ?

那思路就很明确啦,这个? = 369 XOR 258 = 115 第三个题

image-20221023111504427

这里想考察的就是如何把字母转换成数字,有一个东西叫ascii码,不知道的可以百度一下

那就简单了,转换成数字再异或一次就可以了

image-20221023111531320

97 XOR 122 = 27 那所以问题回答正确就可以得到flag:

image-20221023111554821

第一种解题方式就是很正常的答题,那第二种就是逆向破解这个程序,然后获取源码拿到flag 第二种: 从程序的图标看得出来这个是python编写的一个exe程序

image-20221023111623066

具体的自行百度 那接下来就是先获取源码: 这里使用到一个工具,(也可以叫脚本)叫做pyinstxtractor-master (用法自行百度) 那么运行脚本之后就可以得到一个文件夹

image-20221023111648655

这里有个re1.pyc的文件很不一样 用文本打开就能看到flag

py2

出题人:P1tie5

同上一题,用第二种办法,把exe转化成pyc文件,用文本格式打开即可得到flag 但是需要注意的是:

image-20221023111714279

当中出现了"base64"的字样,那自然是flag被加密了

找到那串字符串"TlNTQ1RGe29oaGghXzNhc3lfcHlyZX0Kz"

base64解码即可.

pypy

出题人:djc

其他处理同上面的题

反编译看代码 可以看到

def init_S():
   for i in range(256):
       S.append(i)


def init_T():
   global Key
   Key = 'abcdefg'
   keylen = len(Key)
   for i in range(256):
       tmp = Key[i % keylen]
       T.append(tmp)


def swap_S():
   j = 0
   for i in range(256):
       j = (j + S[i] + ord(T[i])) % 256
       tmp = S[i]
       S[i] = S[j]
       S[j] = tmp


def Get_KeyStream():
   txtlen = len(text)
  (j, t) = (0, 0)
   for i in range(txtlen):
       i = i % 256
       j = (j + S[i]) % 256
       tmp = S[i]
       S[i] = S[j]
       S[j] = tmp
       t = (S[i] + S[j]) % 256
       KeyStream.append(S[t])


def Get_code():
   res = []
   for i in range(len(text)):
       res.append(ord(text[i]) ^ KeyStream[i])

   return res

可以发现这题实际上是在考察对加密算法的熟悉程度

这里是 RC4

使用解密算法即可求出flag

android

出题人:djc

最简单的安卓 本身只是想考察环境

使用反编译 打开就能看见flag

有关具体的反编译工具或是环境不在这里赘述

android2

出题人:Dkymore

安卓异或 但是有个坑 ( 没怎么藏 )

随便选择一个反编译dex的工具 反编译dex 转java可知

有3个关键的类 使用工具转java代码可知

  • Encoder
public class Encoder {
   private int key = 0x075bcd15;

   public Encoder() {
  }

   public String encode(String str) {
       StringBuilder sb = new StringBuilder();
       for (char c : str.toCharArray()) {
           sb.append((char) (c ^ this.key));
      }
       return sb.toString();
  }
}

分析代码 可知这是一个异或函数 把字符串的每一位和 key 异或

  • MainActivity
protected void onCreate(Bundle bundle) {
       MainActivity.super.onCreate(bundle);
       setContentView(0x7f0b001c);
       encoder = new Encoder();
       mainActlvity = new MainActlvity();
      ((Button) findViewById(0x7f080057)).setOnClickListener(new -$.Lambda.MainActivity.i-SDaQT6aGr2btgF05Lf-fvXXSo(this, (EditText) findViewById(0x7f080090)));
  }

   public void lambda$onCreate$0$MainActivity(EditText editText, View view) {
       System.out.println(encoder.encode(editText.getText().toString()));
       if (encoder.encode(editText.getText().toString()).equals("棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌")) {
           Toast.makeText(this, "YES", 0).show();
      } else {
           Toast.makeText(this, "NO", 0).show();
      }
  }

分析代码 可知 用户输入经过 Encode 之后 和 一个静态字符串比较

如果仔细分析一下代码 可知 在创建时 调用了MainActlvity

  • MainActlvity
public class MainActlvity {
   public MainActlvity() {
       try {
           Field declaredField = Encoder.class.getDeclaredField("key");
           declaredField.setAccessible(true);
           declaredField.set(MainActivity.encoder, 0x3ade68b1);
      } catch (IllegalAccessException | NoSuchFieldException e) {
           e.printStackTrace();
      }
  }
}

分析代码可知 这里把 Encode key 的值掉包成了 0x3ade68b1

综合上述本题其实就是一个最简单的异或 把 key 掉包了 如果仔细分析了代码 或者使用动态调试 都能发现

最后异或一下得出flag NSSCTF{apkYYDS}

当然 由于出题者偷懒 NSSCTF 的固定前缀也夹在密文中了

所以 通过这个固定前缀也能得到正确的密钥

wasm

出题人:Dkymore

这道题 其实没有指望有新生能做出来 (纯纯的撑场子题)

但是由于出题人偷懒 这就是之前 NSSCTF ROUND4的同一道题

甚至flag都没改 (^_^) 所有还是有人发现了这点

源代码 密码1234

包含了 wasm + 算法分析 + z3

反编译wasm

使用 wabt 中的 wasm-decompile 反编译代码

动态调试

node --inspect-brk index.js

并在chrome中打开

详情请搜索nodejs调试

分析代码

分析index.js可知目标函数为 check(stringArray)->bool

在wasm中找到

// 去除了无关代码
function assembly_index_check(a:int):int {
e =
{
if (lib_array_Array_i32_get_length(a) != 38) {
e = 0;
return e; //长度38
unreachable;
}
lib_memory_stack_pointer[0]:int =
(b = lib_array_Array_i32_slice(a, 7, -1));
// 切片 7,-1
var c:int = 0;
// 循环30次
loop L_f {
var d:int = c < lib_array_Array_i32_get_length(b);
if (d) {
//执行这俩
assembly_index_reverse(b);
assembly_index_rotate(b, 1);
label B_h:
c = c + 1;
continue L_f;
}
}
//执行这俩
// 理解为
// lp(context.slice(0,10)) && rp(context.slice(10))
// flag左边执行lp 右边执行rp
if (assembly_index_lp({
e = lib_array_Array_i32_slice(b, 0, 10);
lib_memory_stack_pointer[1]:int = e;
e;
label B_i:
})) {
assembly_index_rp(
{
e = lib_array_Array_i32_slice(b, 10, lib_builtins_i32_MAX_VALUE);
lib_memory_stack_pointer[1]:int = e;
e;
label B_k:
})
} else {
0
}
}
return e;
}

接着分析相关函数

function assembly_index_reverse(a:int) {
// 其实就是把内容翻转
// 使用双指针 代码参考 https://leetcode.cn/problems/reverse-string/solution/fan-zhuan-zi-fu-chuan-by-leetcode-solution/
var c:int;
var d:int;
var b:int = lib_array_Array_i32_get_length(a);
c = 0;
d = b - 1;
label B_a:
loop L_c {
var e:int = c < d;
if (e) {
var f:int = lib_array_Array_i32_get(a, c);
lib_array_Array_i32_set(a, c, lib_array_Array_i32_get(a, d));
lib_array_Array_i32_set(a, d, f);
label B_e:
c = c + 1;
d = d - 1;
label B_f:
continue L_c;
}
}
label B_b:
}


function assembly_index_rotate(a:int, b:int) {
// 同上 把内容移动b位 这里恒定位1
// 使用环状替换
// https://leetcode.cn/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
var c:int = lib_array_Array_i32_get_length(a);
b = b % c;
var d:int = assembly_index_gcd(b, c);
var e:int = 0;
loop L_b {
var f:int = e < d;
if (f) {
var g:int = e;
var h:int = lib_array_Array_i32_get(a, e);
loop L_f {
var i:int = (g + b) % c;
var j:int = lib_array_Array_i32_get(a, i);
lib_array_Array_i32_set(a, i, h);
h = j;
g = i;
if (e != g) continue L_f;
}
label B_e:
label B_d:
e = e + 1;
continue L_b;
}
}
label B_a:
}

// 这里这两函数都执行了30次 其实就什么都没干 qwq
// 这点可以通过动态调试发现
// 或是直接把代码弄出来实际运行一下



function assembly_index_lp(a:int):int {
return
if (if (if (if (if (if (if (if (if (lib_array_Array_i32_get(a, 0) + lib_array_Array_i32_get(a, 5) ==
lib_array_Array_i32_get(a, 1) + lib_array_Array_i32_get(a, 9)) {
lib_array_Array_i32_get(a, 0) + lib_array_Array_i32_get(a, 1) +
lib_array_Array_i32_get(a, 2) +
lib_array_Array_i32_get(a, 3) +
lib_array_Array_i32_get(a, 4) +
lib_array_Array_i32_get(a, 5) +
lib_array_Array_i32_get(a, 6) +
lib_array_Array_i32_get(a, 7) +
lib_array_Array_i32_get(a, 8) +
lib_array_Array_i32_get(a, 9) ==
1022
} else {
0
}) {
lib_array_Array_i32_get(a, 7) - lib_array_Array_i32_get(a, 8) == 10
} else {
0
}) {
lib_array_Array_i32_get(a, 3) + lib_array_Array_i32_get(a, 2) +
lib_array_Array_i32_get(a, 1) ==
330
} else {
0
}) {
lib_array_Array_i32_get(a, 5) * lib_array_Array_i32_get(a, 6) *
lib_array_Array_i32_get(a, 8) ==
617500
} else {
0
}) {
lib_array_Array_i32_get(a, 6) * 2 ==
lib_array_Array_i32_get(a, 3) + 15
} else {
0
}) {
lib_array_Array_i32_get(a, 7) ==
lib_array_Array_i32_get(a, 5) + lib_array_Array_i32_get(a, 4) -
lib_array_Array_i32_get(a, 2) +
3
} else {
0
}) {
lib_array_Array_i32_get(a, 8) + lib_array_Array_i32_get(a, 4) == 209
} else {
0
}) {
lib_array_Array_i32_get(a, 1) + lib_array_Array_i32_get(a, 8) +
lib_array_Array_i32_get(a, 9) -
lib_array_Array_i32_get(a, 4) ==
204
} else {
0
}) {
lib_array_Array_i32_get(a, 0) * lib_array_Array_i32_get(a, 1) *
lib_array_Array_i32_get(a, 2) ==
1350628
} else {
0
}
}
// 不难看出lp本质上是需要同时满足一大串条件
// 当然还有隐藏的 ascii码范围
(l[0] +l[5] == l[1] +l[9]) &&
(l[0] + l[1] + l[2] + l[3] + l[4] + l[5] + l[6] + l[7] + l[8] + l[9] == 1022) &&
(l[7] - l[8] == 10) &&
(l[3]+ l[2]+ l[1] == 330) &&
(l[5]*l[6]*l[8] == 617500) &&
(l[6]*2 == l[3] + 15) &&
(l[7] == l[5] + l[4] - l[2] + 3) &&
(l[8] + l[4] == 209) &&
(l[1] + l[8] + l[9] - l[4] == 204) &&
(l[0]*l[1]*l[2] == 1350628)
// 本质解 N元一次的方程
//当然 你可以选择手算
//不过 更为高效的方法是选择 SMT 工具 或者matlab之类的
//比如python z3-solver
//解得 vvasm_And_



function assembly_index_rp(a:int):int {
var c:int;
var e:int;
lib_memory_stack_pointer = lib_memory_stack_pointer - 4;
stack_check();
label B_a:
lib_memory_stack_pointer[0]:int = 0;
e =
{
lib_memory_stack_pointer[0]:int =
(c = lib_rt_newArray(20, 2, 3, 528));
var b:int = 0;
loop L_d {
var d:int = b < lib_array_Array_i32_get_length(a);
if (d) {
if (lib_array_Array_i32_get(c, b) == (lib_array_Array_i32_get(a, b) ^ 2)) {
lib_array_Array_i32_set(c, b, lib_array_Array_i32_get(a, b))
} else {
e = 0;
return e;
unreachable;
}
label B_f:
b = b + 1;
continue L_d;
}
label B_c:
1;
label B_b:
}
return e;
}
// rp 相对简单不少 就是普通的异或 其中密文在wasm的顶端
// 密文 vjcliq]dmp]{mwp]umpi
// 解得 thanks_for_your_work

合并flag可得

NSSCTF{vvasm_And_thanks_for_your_work}

感谢观看我的博客~
SWPU NSS 2022 秋季招新赛 Reverse 出题人笔记
https://www.wd-ljt.com/post/1024/892.html
来源于问谛居,转载记得联系作者哟~
THE END
分享
二维码
海报
SWPU NSS 2022 秋季招新赛 Reverse 出题人笔记
贪吃蛇 出题人:Dkymore 这道题其实是希望大家能用ctf的方式做出来 而不是玩上60分 CE方法 可以使用 CE 修改分数 但是你会发现修改分数没有用……
<<上一篇
下一篇>>