当前位置:网站首页>[安网杯 2021] REV WP
[安网杯 2021] REV WP
2022-07-01 13:22:00 【fa1c4】
hit_re
如果报dll缺失错误, 在https://www.dll-files.com/下载相应的 32 / 64 bits 的dll文件拷贝到C:\Windows\System32或者C:\Windows\SysWOW64文件夹下即可运行

无壳, 拖进IDA32, 直接逆main函数
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
int result; // eax
int v4; // eax
int v5; // [esp-4h] [ebp-414h]
int v6; // [esp-4h] [ebp-414h]
int (__cdecl *v7)(int); // [esp-4h] [ebp-414h]
int v8; // [esp+0h] [ebp-410h]
int v9; // [esp+0h] [ebp-410h]
int v10; // [esp+0h] [ebp-410h]
int v11; // [esp+0h] [ebp-410h]
int v12; // [esp+0h] [ebp-410h]
int v13; // [esp+0h] [ebp-410h]
int v14; // [esp+0h] [ebp-410h]
int v15; // [esp+0h] [ebp-410h]
int v16; // [esp+0h] [ebp-410h]
int v17; // [esp+4h] [ebp-40Ch]
int v18; // [esp+4h] [ebp-40Ch]
int v19; // [esp+4h] [ebp-40Ch]
int v20; // [esp+4h] [ebp-40Ch]
int v21; // [esp+4h] [ebp-40Ch]
int v22; // [esp+4h] [ebp-40Ch]
int v23; // [esp+10h] [ebp-400h]
int v24; // [esp+18h] [ebp-3F8h]
void *v25; // [esp+24h] [ebp-3ECh]
int v26; // [esp+30h] [ebp-3E0h]
int v27; // [esp+30h] [ebp-3E0h]
int v28; // [esp+38h] [ebp-3D8h]
int v29; // [esp+38h] [ebp-3D8h]
int v30[9]; // [esp+4Ch] [ebp-3C4h] BYREF
char v31[36]; // [esp+70h] [ebp-3A0h] BYREF
int v32[9]; // [esp+94h] [ebp-37Ch] BYREF
char v33[36]; // [esp+12Ch] [ebp-2E4h] BYREF
char T_F; // [esp+1C7h] [ebp-249h]
char act; // [esp+36Bh] [ebp-A5h]
char *q; // [esp+374h] [ebp-9Ch]
char *p; // [esp+380h] [ebp-90h]
char *str_in; // [esp+38Ch] [ebp-84h]
char v39; // [esp+39Bh] [ebp-75h]
char *j; // [esp+3A4h] [ebp-6Ch]
char *i; // [esp+3B0h] [ebp-60h]
char *moves; // [esp+3BCh] [ebp-54h]
int not_right_moves; // [esp+3C8h] [ebp-48h]
int right_moves; // [esp+3D4h] [ebp-3Ch]
char data_in[32]; // [esp+3E0h] [ebp-30h] BYREF
int v46; // [esp+40Ch] [ebp-4h]
__CheckForDebuggerJustMyCode(&unk_42E069);
print(std::cout, "your solution: ");
sub_41113B(v8, v17);
v46 = 0;
readin(std::cin, data_in);
if ( moves_count(v9, v18) != 50 ) // input count 50
goto fail;
right_moves = 0;
not_right_moves = 0;
moves = data_in;
i = (char *)sub_41105A(v10, v19);
j = (char *)sub_411005(v11, v20);
while ( i != j )
{
v39 = *i;
if ( v39 == 'd' )
{
++right_moves;
if ( not_right_moves != 6 && not_right_moves != 2 )
_exit(1);
not_right_moves = 0;
}
else
{
++not_right_moves;
}
++i;
}
if ( right_moves == 10 ) // right moves 10 times
{
str_in = data_in;
p = (char *)sub_41105A(v10, v19);
q = (char *)sub_411005(v12, v21);
while ( p != q )
{
act = *p;
switch ( act )
{
case 'a':
--left_right;
break;
case 'd':
++left_right;
break;
case 's':
++up_down;
break;
case 'w':
--up_down;
break;
default:
_exit(-1);
}
if ( map[11 * up_down + left_right] != 1 )// == 1 can move in
_exit(-2);
++p;
}
sub_4111C2((int)data_in);
v26 = sub_4113E8((int)v33);
LOBYTE(v46) = 1;
T_F = sub_4114D3("dcc1df36a15968fb206fe52294bb4130", v26);
LOBYTE(v46) = 0;
sub_4114AB(v13, v22);
if ( T_F )
{
v28 = print(std::cout, "flag is: flag{");
v27 = sub_41160E(data_in, (int)v32, 0, 0x10u);
LOBYTE(v46) = 2;
sub_4111C2(v27);
v25 = (void *)sub_4113E8((int)v31);
LOBYTE(v46) = 3;
v24 = sub_41160E(v25, (int)v30, 0, 0x10u);
LOBYTE(v46) = 4;
v4 = sub_411451(v28, v24);
v23 = print(v4, "}");
std::ostream::operator<<(v23);
LOBYTE(v46) = 3;
sub_4114AB((int)sub_411564, v14);
LOBYTE(v46) = 2;
sub_4114AB(v5, v15);
LOBYTE(v46) = 0;
sub_4114AB(v6, v16);
}
else
{
v29 = print(std::cout, "a little deviation");
v7 = sub_411564;
std::ostream::operator<<(v29);
}
system("pause");
v46 = -1;
sub_4114AB((int)v7, v14);
result = 0;
}
else
{
fail:
v46 = -1;
sub_4114AB(v10, v19);
result = -10;
}
return result;
}
主要逻辑是走出地图, 要求步数恰好为50步, 并且往右走10次, 而且往右走之前需要往其他方向走2或者6次, 提取出地图数据
import idaapi
addr = 0x0042B008
arr = []
for i in range(275):
arr.append(idaapi.get_dword(addr + 4*i))
print(arr)
打印出地图
mapdata = [1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
maps = []
for i in range(25):
maps.append(mapdata[i*11: i*11+11])
for _ in maps:
print(_)
''' [1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0] [1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0] [1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1] [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1] [0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1] [0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0] [1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0] [1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0] [1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1] [1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0] [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0] [1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0] [0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1] [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1] [1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1] [1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1] [1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1] [1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0] [1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0] [1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0] [1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] '''
写一个算法搜索满足条件的路径, 并且找到一个路径需要和MD5值dcc1df36a15968fb206fe52294bb4130比较, 匹配hash值成功的50步路径即为解
这个路径还需要注意, 因为main函数流程中要求往右的次数为10, 显然不能通过往左走凑步数, 因为往左走1次要到达右下角至少需要11次往右走, 那就不符合判断条件, 所以为了凑步数只能上下往返, 因此可以判断路径中不包含’a’, 只包含’w’, ‘s’, ‘d’, 而且根据往右走之前经过距上次往右走的步数, 要么是2步, 要么是6步, 所以可以得到固定的往返模式来凑步数, 接下来就变成算法题
def DFS(step, hlevel, path):
if step == 6:
if hlevel == 2:
print(path)
return
if hlevel == 0:
DFS(step + 1, hlevel + 1, path+'s')
elif hlevel == 1:
DFS(step + 1, hlevel + 1, path+'s')
DFS(step + 1, hlevel - 1, path+'w')
else:
DFS(step + 1, hlevel - 1, path+'w')
DFS(0, 0, '')
''' sswsws sswwss swssws swswss '''
可见上下往返的6步模式有4种, 那么只需要用这4种模式凑步数即可, 最短路径是ssd * 10总共30步, 所以需要引入5次往返模式多凑20步, C 10 5 ∗ 4 5 = 258048 C_{10}^5 * 4^5 = 258048 C105∗45=258048种可能性进行回溯爆破, 其实只需要大概3s
from itertools import combinations
from hashlib import *
patterns = ['swswssd','swsswsd','sswwssd','sswswsd']
L = [_ for _ in range(10)]
coms = list(combinations(L, 5))
# print(coms)
# paths = ['ssd' for _ in range(10)]
# count = 0
# path = ''.join(paths)
# print(path, len(path))
def BackTrace(step, paths, comb):
if step == 10:
path = ''.join(paths)
if md5(path.encode(encoding='UTF-8')).hexdigest() == 'dcc1df36a15968fb206fe52294bb4130':
print('find the flag!!!')
print(path)
print()
return
if step not in comb:
BackTrace(step + 1, paths, comb)
else:
paths[step] = patterns[0]
BackTrace(step + 1, paths, comb)
paths[step] = patterns[1]
BackTrace(step + 1, paths, comb)
paths[step] = patterns[2]
BackTrace(step + 1, paths, comb)
paths[step] = patterns[3]
BackTrace(step + 1, paths, comb)
# print(len(coms))
for comb in coms:
paths = ['ssd' for _ in range(10)]
BackTrace(0, paths, comb)
# path = 'ssdsswswsdssdswswssdssdswsswsdsswswsdssdssdswswssd'
# print(md5(path.encode(encoding='UTF-8')).hexdigest() == 'dcc1df36a15968fb206fe52294bb4130')

pypy
python文件打包的exe, 用pyinstxtractor解析
https://github.com/extremecoders-re/pyinstxtractor
pyinstxtractor.py解压出文件夹, 这里用python3.7才行, 需要和压缩成exe文件所用的python版本一致
[email protected]:/mnt/k/competition/安网杯/re/pypy$ python3.7 pyinstxtractor.py pypy.exe
[+] Processing pypy.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.7
[+] Length of package: 6230873 bytes
[+] Found 61 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pypy.pyc
[+] Found 133 files in PYZ archive
[+] Successfully extracted pyinstaller archive: pypy.exe
You can now use a python decompiler on the pyc files within the extracted directory
然后用uncompyle6把pypy.pyc文件逆回py文件uncompyle6 pypy.pyc > pypy.py
得到源码
# uncompyle6 version 3.8.0
# Python bytecode 3.7.0 (3394)
# Decompiled from: Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)]
# Embedded file name: pypy.py
import hashlib
if __name__ == '__main__':
nums = []
a, b, c = (3001, 2137, 4729)
n = 100000
num = 1
while len(nums) != n:
num_copy = num
while num_copy != 1:
if num_copy % a == 0:
num_copy //= a
elif num_copy % b == 0:
num_copy //= b
elif num_copy % c == 0:
num_copy //= c
else:
break
if num_copy == 1:
nums.append(num)
num += 1
print(nums[(n - 1)])
m = hashlib.md5()
b = str(nums[(n - 1)]).encode(encoding='utf-8')
m.update(b)
result = m.hexdigest()
print('flag{' + result + '}')
# okay decompiling pypy.pyc
简单来说就是求以3001, 2137,4729为因数组成的倍数, 从小到大排序的第100000个数的MD5值
算法题, 用优先队列heapq优化性能, 每次向优先队列里加入Min * 3001, Min * 2137, Min * 4729贪心取得当前最小的倍数, 当heapq弹出100000个Min, 则得到答案
from hashlib import *
from heapq import *
ps = [3001, 2137, 4729]
heap = []
heappush(heap, 1)
occupied = set()
occupied.add(1)
count = 0
Min = 0
while True:
Min = heappop(heap)
count += 1
if count == 100000: break
for i in range(3):
tmp = Min * ps[i]
if tmp not in occupied:
heappush(heap, tmp)
occupied.add(tmp)
print(Min)
print('flag{' + md5(str(Min).encode(encoding='UTF-8')).hexdigest() + '}')
''' 16405850262570740513897217717623720600448855987320514551726154873739883293720282851034424371051874484044854674904735438772866326784386465461577479345634270005309256879590279090175542403199472872896278587926077044001237403554885317937416574659330592944654425785521663598285833017718525414609 flag{ba64f885157a04966c5173fb24590032} '''
总结
这是去年打的第一次线下赛, 时隔一年来补一下题, 当时因为禁止联网(虽然赛场全是热点, 我当时开热点还被捉了, xs), 环境配不起来REV这两题都没做出来, 后来各种事一直没补题, 现在感觉积累足够了, 差不多可以把近两年的赛题都做一做.
总体来说这两题逻辑不算很复杂, 有的函数调用链很深逻辑判断不了, 就直觉猜加动调验证, 软件加密也上了花指令反调试或者保护壳(虽然没啥干扰), 逆向出来就变成算法题了, 算法题多刷刷也不算特别难, 主要是能联网, 难度会低很多.
边栏推荐
- 关于佛萨奇2.0“Meta Force原力元宇宙系统开发逻辑方案(详情)
- Three questions about scientific entrepreneurship: timing, pain points and important decisions
- leetcode 322. Coin change (medium)
- Asp.netcore利用dynamic简化数据库访问
- Feign & Eureka & zuul & hystrix process
- Sharing with the best paper winner of CV Summit: how is a good paper refined?
- 机器学习—性能度量
- word2vec训练中文词向量
- Detailed explanation of leetcode reconstruction binary tree [easy to understand]
- Listen in the network
猜你喜欢

Several models of IO blocking, non blocking, IO multiplexing, signal driven and asynchronous IO

波浪动画彩色五角星loader加载js特效

Meta enlarge again! VR new model posted on CVPR oral: read and understand voice like a human

Beidou communication module Beidou GPS module Beidou communication terminal DTU

Summary of interview questions (1) HTTPS man in the middle attack, the principle of concurrenthashmap, serialVersionUID constant, redis single thread,

介绍一种对 SAP GUI 里的收藏夹事务码管理工具增强的实现方案

Content Audit Technology

Colorful five pointed star SVG dynamic web page background JS special effect

minimum spanning tree

流量管理技术
随机推荐
spark源码(五)DAGScheduler TaskScheduler如何配合提交任务,application、job、stage、taskset、task对应关系是什么?
Blind box NFT digital collection platform system development (build source code)
开源者的自我修养|为 ShardingSphere 贡献了千万行代码的程序员,后来当了 CEO
Report on the 14th five year plan and future development trend of China's integrated circuit packaging industry Ⓓ 2022 ~ 2028
MySQL六十六问,两万字+五十图详解!复习必备
MySQL报错1040Too many connections的原因以及解决方案
About fossage 2.0 "meta force meta universe system development logic scheme (details)
ArrayList capacity expansion mechanism and thread safety
Meta enlarge again! VR new model posted on CVPR oral: read and understand voice like a human
Jenkins+webhooks- multi branch parametric construction-
简单的两个圆球loading加载
1.8新特性-List
陈宇(Aqua)-安全-&gt;云安全-&gt;多云安全
Simplex, half duplex, full duplex, TDD and FDD
Computer network interview knowledge points
Sharing with the best paper winner of CV Summit: how is a good paper refined?
In the next stage of digital transformation, digital twin manufacturer Youyi technology announced that it had completed a financing of more than 300 million yuan
Detailed explanation of leetcode reconstruction binary tree [easy to understand]
Shangtang technology crash: a script written at the time of IPO
Summary of interview questions (1) HTTPS man in the middle attack, the principle of concurrenthashmap, serialVersionUID constant, redis single thread,