当前位置:网站首页>[安网杯 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这两题都没做出来, 后来各种事一直没补题, 现在感觉积累足够了, 差不多可以把近两年的赛题都做一做.
总体来说这两题逻辑不算很复杂, 有的函数调用链很深逻辑判断不了, 就直觉猜加动调验证, 软件加密也上了花指令反调试或者保护壳(虽然没啥干扰), 逆向出来就变成算法题了, 算法题多刷刷也不算特别难, 主要是能联网, 难度会低很多.
边栏推荐
- Huawei HMS core joins hands with hypergraph to inject new momentum into 3D GIS
- China NdYAG crystal market research conclusion and development strategy proposal report Ⓥ 2022 ~ 2028
- Yarn restart applications record recovery
- Application of 5g industrial gateway in scientific and technological overload control; off-site joint law enforcement for over limit, overweight and overspeed
- MySQL六十六问,两万字+五十图详解!复习必备
- 1.8 new features list
- 彩色五角星SVG动态网页背景js特效
- 内容审计技术
- Reasons for MySQL reporting 1040too many connections and Solutions
- Machine learning summary (I): linear regression, ridge regression, Lasso regression
猜你喜欢

Beidou communication module Beidou GPS module Beidou communication terminal DTU

ZABBIX 6.0 source code installation and ha configuration

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

Huawei HMS core joins hands with hypergraph to inject new momentum into 3D GIS

minimum spanning tree

孔松(信通院)-数字化时代云安全能力建设及趋势
Example code of second kill based on MySQL optimistic lock

Google Earth Engine(GEE)——全球人类居住区网格数据 1975-1990-2000-2014 (P2016)

啟動solr報錯The stack size specified is too small,Specify at least 328k

A Fletter version of Notepad
随机推荐
进入前六!博云在中国云管理软件市场销量排行持续上升
Yarn restart applications record recovery
基于mysql乐观锁实现秒杀的示例代码
Analysis report on the development pattern of China's smart emergency industry and the 14th five year plan Ⓠ 2022 ~ 2028
SAP intelligent robot process automation (IRPA) solution sharing
Analysis report on the development trend and prospect scale of silicon intermediary industry in the world and China Ⓩ 2022 ~ 2027
Simplex, half duplex, full duplex, TDD and FDD
Introduction to topological sorting
Apache-atlas-2.2.0 independent compilation and deployment
How much money do novices prepare to play futures? Is agricultural products OK?
Chen Yu (Aqua) - Safety - & gt; Cloud Security - & gt; Multicloud security
JS discolored Lego building blocks
Explain IO multiplexing, select, poll, epoll in detail
孔松(信通院)-数字化时代云安全能力建设及趋势
1.8新特性-List
Leetcode第一题:两数之和(3种语言)
Who should I know when opening a stock account? Is it actually safe to open an account online?
Arthas use
3.4 《数据库系统概论》之数据查询—SELECT(单表查询、连接查询、嵌套查询、集合查询、多表查询)
Meta enlarge again! VR new model posted on CVPR oral: read and understand voice like a human