当前位置: 首页 > news >正文

Polar CTF Reverse简单 刷题笔记

看着大佬同学在写,我也得不甘示弱啊,刷就完了,不过后边那几道是真不简单啊

shell:

一上来就要脱壳,好家伙

不过,一脱完放进ida就可以看到flag

PE结构:

拖进DIE发现文件头不对

运行一下就行了

拼接:

文件头是zip改一下

32位,进入main函数,拼一块就行了

加加减减:

32位,进入main函数

一个简单的算法,将flag的每个字符的ASCLL码-1就是str2,逆向代码:

str1 = "ek`fz5123086/ce7ac7/`4a81`6/87b`b28a5|"
flag = " "
for i in range(len(str1)):flag += chr(ord(str1[i])-1)
print(flag)

康师傅:

32位,进入main函数

就是将str1和9异或即可

代码:

str1 = 'oehnr8>?;<?:9k>09;hj00o>:<o?8lh;8h9l;t'
flag = ''
for i in range(0,len(str1)):flag += chr(ord(str1[i]) ^ 9)
print(flag)

另辟蹊径:

运行程序,这是一个改值题,需要用Cheat Engine

这是需要运行进程中扫描

将其数值改为1,再运行

use_jadx_open_it:

apk文件用jadx打开,查找main函数

re2:

64位,进入main函数

代码就是将flag和输入的分别base64加密作比较,所以flag就是这个

layout:

apk文件,进入jadx,有个假的flag

用到雷电模拟器,打开

发现flag重合了,在开发助手用布局查看

Why32:

找一下算法,main函数里没找到啥线索,shift + F12查找字符串,看到敏感信息,跟进

先逆向算法

a = '2gfe8c8c4cde574f7:c6c;:;3;7;2gf:'
flag = ''
for i in range(0,len(a)):flag += chr(ord(a[i]) - 2)
print(flag)

但是提交了不对,看代码最后说对了一半,结合题目,还要MD5加密

?64:

64位,进入main函数,是个算法

让AI分析一下,这里详细解释一下这个v6数组,本来是_WORD[12],1个元素占2个字节,但是下面那个用了char指针,这时要按照字符串的存储读写方式,一个元素占一个字节,而接着下面的v6[8]=0,还是按照_WORD类型进行读取,所以这里截取相当于没有,还是全部加密

而这个加密方法简单,就是将字符串对应ASCLL值+1

a = 'YlwAY08ob1gkTlT<'
flag = ''
for i in range(0,len(a)):flag += chr(ord(a[i]) + 1)
print(flag)

其实以上步骤还可以简单通过运行这个程序获得,这是看了别人的博客知道的

一眼base64,解一下

但是提交不对,还得MD5加密

Sign Up:

64位,进入main函数,check就是算法

key_num-1,key_password-2,找到对应数据

key_num-1,key_password-2,找到对应数据

由此得到账号:081057009密码:pmmr

easyre1:

找到加密函数。但是具体数据时根据地址找到

str = "d^XSAozQPU^WOBU[VQOATZSE@AZZVOF"
str2 = "5055045045055045055045055045055"
flag = ""
for i in range(len(str2)):flag += chr((ord(str[i])+1)^ord(str2[i]))
print(flag)

babyRe:

类C语言,看到这样的很难受,进入main函数,endoce函数

可以让AI转C语言,大概思路就是将每个字符的ASCLL码+2就是flag,下一步就是找字符串,那就快捷键找字符串就行了

代码:

str = "asdfgcvbnmjgtlop"
flag = " "
for i in range(len(str)):flag += chr(ord(str[i]) + 2)
print (flag)

C^:

32位,进入main函数

fun1函数是加密函数

而check函数是验证函数

三者结合一下,就是v6[2]是flag存储的起始位置,也就是a1,而v8是flag的长度,也就是a2。加密算法就是将原始flag和1进行异或就是s

逆向代码:

str1 = "shfiu777"
flag = " "
for i in range(len(str1)):flag += chr(ord(str1[i])^1)
print(flag)

直接提交不对,还需要MD5加密

一个flag劈三瓣儿:

32位,进入main函数,三部分连起来即可

EasyCPP2:

64位,main函数里的encode加密函数很关键

查看flag

逆向代码:

cipher='qisngksofhuivvmg'
flag=''
for i in cipher:flag+=chr((ord(i)+3)^1)
print(flag)

crc:

64位,进入main函数,通过strmcpy函数从v11提取不同位置和长度的字符串到v10,进行magic函数处理后与目标字符串比较。进入magic函数发现是CRC32爆破

借用一下大佬的通用脚本用来对不同长度的字符串进行爆破:

import zlib
from itertools import product
def cacl_crc(s):'''计算crc'''crc=zlib.crc32(s.encode('utf-8'))&0xffffffff#有符号数字转为无符号return f'{crc:08x}'
# print(cacl_crc('text'))测试用例
# 分段规则:(起始索引, 长度, 目标CRC32)
def brute(target,length,chars):'''target:已知字符串chars:爆破字符集'''for combo in product(chars,repeat=length):candidate=''.join(combo)if cacl_crc(candidate) == target:print(f"找到原文,是{candidate}")return candidatereturn 0
def main():# 常用字符集(可根据题目调整,比如去掉大写字母)# 扩展字符集:包含大小写字母、数字、下划线、连字符、感叹号、问号、括号等常见符号chars = ("abcdefghijklmnopqrstuvwxyz"  # 小写字母"ABCDEFGHIJKLMNOPQRSTUVWXYZ"  # 大写字母"0123456789"                  # 数字"_-!@#$%^&*()[]{}<>?.,;:|=+"  # 常见符号(根据CTF题目风格调整,去掉可能不相关的)
)result_segments = []segments = [(0, 4, "d1f4eb9a"),   # 第1段:从input[0]开始,取4个字符(4, 1, "15d54739"),   # 第2段:从input[4]开始,取1个字符(5, 4, "540bbb08"),   # 第3段:从input[5]开始,取4个字符(9, 2, "3fcbd242"),   # 第4段:从input[9]开始,取2个字符(11, 4, "2479c623"),  # 第5段:从input[11]开始,取4个字符(15, 1, "fcb6e20c")   # 第6段:从input[15]开始,取1个字符
]for i,(start,length,target) in enumerate(segments,1):print(f"开始爆破第{i}段:长度{length},目标CRC32={target}")segment = brute(target, length, chars)if not segment:return print("none")result_segments.append(segment)full_flag="".join(result_segments)print("结果是:"+full_flag)
if __name__ == "__main__":main()

爆破出来不加空格即可

box:

给了文本提示三段key拼到一块就是flag

64位,进入main函数分别分析

第一段key是一个算法

可以写代码:

key=0
c,d,f=0
for i in range(1,22):for j in range(1,2):c += id += cf = d + c - 1
for k in range(33,0,-1):c = f * d / 10key += f * d / 10
print(key)

第二段点开str1就是

第三段是base32加密,解码

解出来的拼到一块MD5加密

HowTo_Login:

需要先脱壳,UPX直接脱

32位,看到一个类似main函数的,点进去

看到Registion Success,跟登录有关,这个应该就是相关函数了

上面是登录邮箱格式验证,要求必须有@,有.,.后有字符,@后面不能紧跟.。那这就好办了,随便输入一个符合格式的就行

下面是一堆ASCLL码,分别转为字符,是CZ9dmq4c8g9G7bAX,这就是登录密码,再根据另一个文本提示,解出来的需要进行32位MD5加密,小写的

ezpack:

需要Aspack stripper脱壳工具https://link.gitcode.com/i/38d0a24f1582f6a288abc9124dbbd10a?uuid_tt_dd=10_37481620410-1752302325925-727688&isLogin=1&from_id=147330619

下载后拖进去就行了,找不到main函数,shift + 12找字符串,发现有Success等词语,跟进,交叉引用找到函数

在sub_sub_401648()函数里找到str2字符串

在sub_401378里找到算法

比较简单的异或,逆向代码即可:

str1 = ">4i44oo4?i=n>:m;8m4=oo4i;>?4>h9m"
flag = ""
for i in range(len(str1)):flag += chr(ord(str1[i]) ^ 12)
print (flag)

L00k_at_h3r3:

Unaspack脱壳,32位,进入main函数

整体是分别对每一段字符串进行加密,加密方式是一样的,都是分别和一个字符异或

那就分别分析写逆向代码

flag = " "
str1 = "lfkmqw"
for i in range(len(str1)):flag += chr(ord(str1[i]) ^ 0xa)
flag1 = " "
str2 = "nqT"
for i in range(len(str2)):flag += chr(ord(str2[i]) ^ 0xb)
flag2 = " "
str3 = "kixS"
for i in range(len(str3)):flag += chr(ord(str3[i]) ^ 0xc)
flag3 = " "
str4 = "ka9jR"
for i in range(len(str4)):flag += chr(ord(str4[i]) ^ 0xd)
flag4 = " "
str5 = "h|>cQ"
for i in range(len(str5)):flag += chr(ord(str5[i]) ^ 0xe)
flag5 = " "
str6 = "g<}<"
for i in range(len(str6)):flag += chr(ord(str6[i]) ^ 0xf)
print(flag+flag1+flag2+flag3+flag4+flag5)

解码器:

64位,进入main函数

重点是encyrpt这个算法

a1就是v5,a2就是v4,a3就是16,对v5的每个字符的ASCLL码加上对应索引i,再取模127,若结果<=31,那么就再加上32,输出v4

其实运行一下程序就有

这个就是v4,那么加密明文就是SELUTE TO LEGEND,提交不对,MD5即可

reserve_fib:

有一个文本,国庆假期放假三天。还有一个程序,64位,进入main函数

好长一段代码,慢慢来吧。前面是读取flag,去掉换行符。这是因为fgets函数输入时,回车后结尾会有换行符,此时字符串长度会多1,这就要替换为结束符就行;并且查看了是否越界。

将字符串转ASCLL码,然后就是输入一个整数,第39行的if语句是计算v7,根据题目给的另一个文本及反编译的算法,v7就是斐波那契数列的第v17项,也就是对第n项的斐波那契数列的计算,最后遍历输出

AI代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-def fib(n: int) -> int:"""按反编译逻辑计算第 n 个斐波那契数(n 从 1 开始,f(1)=1, f(2)=1)"""if n <= 0:return 0if n == 1 or n == 2:return 1a, b = 1, 1for _ in range(n - 2):a, b = b, a + breturn bdef transform_add(orig: str, k: int) -> str:"""对每个字符做 chr(ord(c) + k),并保证结果为单字节字符(取低 8 位)"""out = []for c in orig:out.append(chr((ord(c) + k) & 0xFF))return ''.join(out)def transform_sub(orig: str, k: int) -> str:"""对每个字符做 chr(ord(c) - k),并保证结果为单字节字符(取低 8 位)"""out = []for c in orig:out.append(chr((ord(c) - k) & 0xFF))return ''.join(out)def printable_view(s: str) -> str:return ''.join(ch if 32 <= ord(ch) < 127 else '.' for ch in s)def main():n = 3  # 题目给定orig = "um`svg_lehg_`_l"  # 题目给定原始字符串,长度15k = fib(n)print(f"n = {n}, fib(n) = {k}")print("原始字符串:", orig)out_sub = transform_sub(orig, k)out_add = transform_add(orig, k)print("\n结果(按 Buffer[i] - fib(n)):")print("原始字节视图:", [ord(c) for c in orig])print("字符结果      :", out_sub)print("可打印视图    :", printable_view(out_sub))print("\n结果(按 Buffer[i] + fib(n)):")print("字符结果      :", out_add)print("可打印视图    :", printable_view(out_add))# 方便直接查看可能的 flag 格式print("\n包装为 flag{...} 的候选:")print("flag{", printable_view(out_sub), "}", sep="")print("flag{", printable_view(out_add), "}", sep="")if __name__ == '__main__':main()

答案就是wobuxiangjiaban,但是提交不对,MD5加密

re数独:

第一次碰到这种题,参考着大佬们的博客还有视频写。

一个程序合一个C语言,先看一下C语言是一个9宫格数独求解方法

会发现main这里少了原来数独的数据。还有一个程序,64位,main函数看看,这里额算法其实也是求解数独,那么现在就是要提取原本的数独了

方法一:在VS code里下断点,就是鼠标移到左边有个红点就可以下,一定下在solveSudoku()函数执行后,return函数执行前。右上角有调试,左边就出来了

方法二:AI写的代码直接解出来

#include <stdio.h>
#include <stdbool.h>#define N 9// 打印数独(优化格式,增强可读性)
void printGrid(int grid[N][N]) {for (int r = 0; r < N; r++) {// 每3行打印分隔线(适配3×3子网格)if (r % 3 == 0 && r != 0) {printf("-------------------------\n");}for (int d = 0; d < N; d++) {// 每3列打印分隔符if (d % 3 == 0 && d != 0) {printf(" | ");}printf("%d ", grid[r][d]);}printf("\n");}
}// 检查数字是否可填入当前位置
bool isSafe(int grid[N][N], int row, int col, int num) {for (int x = 0; x < N; x++) {// 检查行、列、3×3子网格是否存在重复数字if (grid[row][x] == num || grid[x][col] == num ||grid[row - row % 3 + x / 3][col - col % 3 + x % 3] == num) {return false;}}return true;
}// 数独求解回溯算法
bool solveSudoku(int grid[N][N]) {int row, col;bool isEmpty = true;// 查找空格(值为0的位置)for (row = 0; row < N; row++) {for (col = 0; col < N; col++) {if (grid[row][col] == 0) {isEmpty = false;break;}}if (!isEmpty) {break;}}// 无空格时说明数独已解if (isEmpty) {return true;}// 尝试填入1-9的数字for (int num = 1; num <= N; num++) {if (isSafe(grid, row, col, num)) {grid[row][col] = num;// 递归求解,若后续空格全部填满则返回成功if (solveSudoku(grid)) {return true;}// 回溯:当前数字无法导致解,恢复为空格grid[row][col] = 0;}}return false; // 无可行解时返回失败
}int main() {// 修复:移除数组最后一行的多余逗号(语法错误核心)int grid[N][N] = {{5, 3, 0, 0, 7, 0, 0, 0, 0},{6, 0, 0, 1, 9, 5, 0, 0, 0},{0, 9, 8, 0, 0, 0, 0, 6, 0},{8, 0, 0, 0, 6, 0, 0, 0, 3},{4, 0, 0, 8, 0, 3, 0, 0, 1},{7, 0, 0, 0, 2, 0, 0, 0, 6},{0, 6, 0, 0, 0, 0, 2, 8, 0},{0, 0, 0, 4, 1, 9, 0, 0, 5},{0, 0, 0, 0, 8, 0, 0, 7, 9} // 移除此处多余的逗号};printf("原始数独:\n");printGrid(grid); // 打印原始数独printf("\n求解结果:\n");if (solveSudoku(grid)) {printGrid(grid); // 求解成功,打印结果} else {printf("No solution exists");}return 0;
}

将最后一行MD5即可

易e:

32位,进入main函数,看不懂。这个程序太难了

看了解题视频,借助大佬某土的插件E-compiler,有个验证按钮

还是看不懂,问AI

主要算法就是将字符转ASCLL码+7,然后转回去为v27,再分别提取v27的高4位和低4位(还是原来长度),选取对应十六字符,拼一块

逆向代码:

# 一行完成解密,列表推导式比字符串拼接更高效
hex_str = "686D38373F6A68383C686B6B3737686A373C3F6C38383D3A406C38396C3A683D"
decrypted = ''.join([chr(ord(c) - 7) for c in bytes.fromhex(hex_str).decode()])
print("解密结果:", decrypted)

Polar_tasks:

64位,进入main函数,但是没找到什么有效信息,大都是初始化变量和运行空间,还有跟运行界面有关,且调用了一些函数。查找字符串,找到跟flag有关

需要计算地址,先查看dword_14001EA00=3

42*3=126,而一个数组占6个字节

126/6=21,也就是索引21

同理,aItsReverse

拼一块即可

tanchi:

打开发现是个贪吃蛇程序。有壳,用UnAspack脱,32位,进入main函数

这代码太长了,复制给AI看看。前面是控制台的相关操作还有用户输入的处理等

最重要的还是从字符串开始的代码

这是做了三轮字符变换。第一轮是将v28和0x23异或,结果为Arglist[0],将v28返回Arglist[1],接着同样的操作,知道碰到结束符

if ( !v28 )goto LABEL_60;v29 = ArgList;do{*v29++ = v28 ^ 0x23;v28 = *v29;}while ( *v29 );

第二轮,若字符为大写,那么v32 = (v30 - 44) % 26 + 65;若是小写,就v32 = (v30 - 76) % 26 + 97。相当于相当于把字母向右循环移动 +21(等于-5)

例如 'a'(97) → (97-76)=21 %26 =21 → +97 = 118 = 'v',确实 'a'->'v'

v30 = ArgList[0];
if ( !ArgList[0] ) goto LABEL_60;
do {if ( (unsigned __int8)(v30 - 97) > 0x19u ) {if ( (unsigned __int8)(v30 - 65) > 0x19u )goto LABEL_53;v32 = (v30 - 44) % 26 + 65;} else {v32 = (v30 - 76) % 26 + 97;}*v52 = v32;
LABEL_53:v33 = *++v31;...
} while ( v33 );

第三轮,对每个字符串c' = (c + 109) % 127,如果结果小于 32(不可打印控制字符),再 +32 以保证至少为可打印 ASCII(范围至少 32..126)

v34 = ArgList[0];
do {v36 = (v34 + 109) % 127;*v35 = v36;if ( v36 < 32 )*v35 = v36 + 32;... next char ...
} while ( v37 );

后面就是打印字符并且控制台显示与循环

那么可以根据这个加密算法写代码获得flag,AI的,Python还在尽力学习当中

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
穷举 v28 并模拟反编译得到的变换:
1) (可选)使用 v28 对原始字节做类似流式的 XOR(与反编译代码语义一致)
2) 对字母做 +21 的环形偏移(即小写:ch -> (ch-97+21)%26 + 97;大写同理)
3) 对每个字符做 (ord + 109) % 127 ,如果结果 < 32 则 +32 以保证可打印
我们穷举 v28 的取值 0..255,并且把 v28==0 视为跳过 XOR 的情况。
在所有结果中搜索包含 "flag{" 的输出并打印候选项。
"""
from typing import OptionalINIT = "`}{gvhBYnllosllYZsZsBkkAooslAiiiskAls"def emulate_transform(initial: str, v28: Optional[int]) -> str:# 步骤0:将字符串转为可变字符数组以便修改orig = list(initial)  # 原始内容,用于 XOR 循环时作为“下一个字节”来源arr = list(initial)   # 如果执行 XOR 步骤,将在 arr 上覆盖结果# 步骤1:反编译代码中的条件性流式 XOR 循环# if (!v28) 跳过该步骤if v28 and v28 != 0:# 按照推断实现语义:# 对 i=0..n-1:#   arr[i] = cur ^ 0x23#   cur = ord(orig[i+1]) if i+1 < len(orig) else 0#   如果 orig[i+1] == 0 则终止(对应 C 字符串以 NUL 结尾)n = len(orig)cur = v28 & 0xfffor i in range(n):arr[i] = chr((cur ^ 0x23) & 0xff)# 准备下一轮的 cur,从原始缓冲的下一个字节读取(如果存在)if i + 1 < n:next_byte = ord(orig[i+1])else:next_byte = 0cur = next_byte# 反编译循环在遇到下一个字节为 NUL 时结束,这里照做if next_byte == 0:break# 注意:如果原始字符串后面有未处理部分,按反编译语义这些位置保持原值# 否则跳过 XOR,arr 保持初始值# 步骤2:对字母进行 +21 的环形偏移(保持大小写)def rot_letter_plus21(ch: str) -> str:o = ord(ch)if 97 <= o <= 122:return chr(((o - 97 + 21) % 26) + 97)if 65 <= o <= 90:return chr(((o - 65 + 21) % 26) + 65)return charr = [rot_letter_plus21(c) for c in arr]# 步骤3:对每个字符做 (ord + 109) % 127,再保证结果 >= 32(可打印)out_chars = []for c in arr:v = (ord(c) + 109) % 127if v < 32:v = v + 32out_chars.append(chr(v))return ''.join(out_chars)def find_flag_candidates(initial):candidates = []# 先尝试 v28 == 0(跳过 XOR),用 0 表示该情况out0 = emulate_transform(initial, 0)candidates.append((0, out0))# 枚举 v28 从 1 到 255for v in range(1, 256):out = emulate_transform(initial, v)candidates.append((v, out))# 对结果按“有趣程度”进行过滤和排序interesting = []for v, s in candidates:lower = s.lower()score = 0# 如果包含 "flag{" 给一个很高的分数if "flag{" in lower:score += 1000# 否则以可打印字符数量作为启发式评分printable = sum(1 for ch in s if 32 <= ord(ch) < 127)score += printableinteresting.append((score, v, s))# 按分数从高到低排序interesting.sort(reverse=True)return interestingdef main():initial = INITres = find_flag_candidates(initial)# 打印前 30 个候选项print("Top 30 candidates (score, v28, output)...\n")for score, v, s in res[:30]:marker = " <-- contains 'flag{'" if "flag{" in s.lower() else ""print(f"v28={v:3d} score={score:4d}  output: {s}{marker}")# 另外单独列出包含 flag{ 的所有候选print("\nAll candidates that include 'flag{' (case-insensitive):")found = Falsefor score, v, s in res:if "flag{" in s.lower():print(f"v28={v:3d}  output: {s}")found = Trueif not found:print("None found. You can inspect top candidates above or try alternative interpretations.")if __name__ == "__main__":main()

http://www.dtcms.com/a/596596.html

相关文章:

  • 刷题日常 2 二叉树中序遍历
  • 从C++到仓颉:一个小型项目的迁移实践与深度思考
  • ⸢ 拾肆-Ⅱ⸥⤳ 实战检验应用实践(下):自动化检验 演练复盘
  • TypeScript中extends与implements的区别
  • 企业网站建设问卷专业网站建设 公司哪家好
  • 建一个网站需要什么条件可以免费观看电视电影
  • ArrowDL BT下载工具v4.2.1中文版安装教程(附详细步骤+下载方法)
  • 高德MCP服务接入
  • 立即执行函数(IIFE)
  • Scratch编程教程 | 从入门到实战创意编程
  • 如何在Keil5中在没有硬件支持的情况下使用Keil的模拟器(Simulator) + 调试窗口输出进行调试
  • YOLOv8改进实战:自研MSAM多尺度注意力机制,通道注意力全面升级,CBAM再进化!
  • 从一场年会看乐鑫科技的创新传承
  • 【系统架构设计师-2025下半年真题】综合知识-参考答案及详解(回忆版)
  • custed谁做的网站大连电商平台有哪些
  • 公司高端网站设计公司沈阳建设厅官方网站
  • 微信小程序必要要安装SSL证书吗?小程序SSL详解
  • PostgreSQL18新功能COPY命令变得更加用户友好
  • 医疗小程序05完善就诊人信息
  • idea AI编程 腾讯云代码助手 CodeBuddy插件安装和使用
  • 湖南益阳网站建设做地坪网站
  • 02-SQLite 为了防止多人同时乱写,把整个数据库文件“当一本账本加锁”
  • 盲盒抽赏小程序一番赏 + 无限赏拓展玩法分析:技术赋能与商业破局
  • 专业网站开发价格wordpress打开自定义很慢
  • 济南建站公司电话网页界面设计与制作邓文达
  • Mysql主从架构的搭建
  • MySQL数据库:表的增删改查 [CRUD](进阶)
  • AI+云计算互融共生,2025AI云产业发展大会即将举行
  • 基于YOLO的深度学习框架用于从胸部X射线图像检测肺炎
  • spring cloud微服务常用组件