re新手的做题体验:蒙蔽蒙蔽,一脸蒙蔽
题目hide:
这是一道加了upx壳的程序,但是但用upx脱壳工具脱不下来,所以只能手动脱壳
因为程序在运行时,会自身进行脱壳,在linux下可以通过dd命令,将它的text段和data段dump下来,然后拼起来,拖进ida中看,但是这给dump下来的二进制文件不可以执行,因为它的不符合elf文件格式
程序dump的话要,要先跳过ptrace这个系统调用,因为这个程序会调用ptrace来反调试,只要在gdb中用catch syscall ptrace这条命令,然后执行到ptrace,将eax设置为0就可以跳过ptrace了 然后通过 cat /proc/(pidof hide)/maps 来打印hide的内存信息
最后通过 dd命令,将hide的text段和data段dump下来
脱壳命令:
sudo dd if=/proc/$(pidof hide) /mem of=hide_dump1 skip=4194304 bs=1c count=827392
sudo dd if=/proc/$(pidof hide)/mem of=hide_dump2 skip=7110656 bs=1c count=20480
cat hide_dump1 hide_dump2 >hide_dump
程序dump下来后就可以脱到ida中去看了
程序的关键代码可以通过string xref 找到。通过查找字符串 快捷键shift + f12 ,找到一些关键的字符串,然后查找有什么函数引用它,然后就可以找到main函数,但是ida静态分析的结果是不正确的,它有些关键代码被隐藏起来了,所以要通过string xref 来找到调用"Enter "字符串的地方,可以发现有两个地方引用了这个字符串,查看另一个调用的地方
跳转到那个地方,发现没有函数,create一个函数后因为syscall所以后面的代码反编译后显示不出来,所以通过查看汇编代码的关键函数的地址,在那create一个function,在反编译就可以查看了
image.png可以发现,输入字符串长度为21,以及关键字符,以及加密后的密文v2
加密函数实现了一个Tea加密算法的变种
将flag_encdump出来,写个解密脚本跑一下,flag的内容就出来了
解密脚本:
脚本来源 : 大佬github
from struct import pack,unpack
arr=[0x52,0xb8,0x13,0x7f,0x35,0x8c,0xf2,0x1b,0xf4,0x63,0x86,0xd2,0x73,0x4f,0x1e,0x31]
ct=map(chr,arr)
def rec8e50(ct):
res=''
for i in range(16):
res+=chr(i^ord(ct[i]))
return res
key=[1883844979,1165112144,2035430262,861484132]
DELTA=0x676E696C
rounds=8
def ul(v):
return v & 0xFFFFFFFF
def rec8cc0(ct):
res=''
for j in range(2):
v0=unpack('I',ct[8*j:8*j+4])[0]
v1=unpack('I',ct[8*j+4:8*j+8])[0]
sum = ul(DELTA * rounds)
for i in range(rounds):
v1 = ul(v1 - ((v0 << 4 ^ v0 >> 5) + v0 ^ sum + key[sum>>11 & 3]))
sum = ul(sum - DELTA)
v0 = ul(v0 - ((v1 << 4 ^ v1 >> 5) + v1 ^ sum + key[sum & 3]))
res += pack('I',v0) + pack('I',v1)
return res
def c8cc0(pt):
res=''
for j in range(2):
v0=unpack('I',pt[8*j:8*j+4])[0]
v1=unpack('I',pt[8*j+4:8*j+8])[0]
sum = 0
for i in range(rounds):
v0 = ul(v0 + ((v1 << 4 ^ v1 >> 5) + v1 ^ sum + key[sum & 3]))
sum = ul(sum + DELTA)
v1 = ul(v1 + ((v0 << 4 ^ v0 >> 5) + v0 ^ sum + key[sum>>11 & 3]))
res += pack('I',v0) + pack('I',v1)
return res
for i in range(3):
ct = rec8e50(ct)
ct = rec8cc0(ct)
print ct
# qwb{f1Nd_TH3HldeC0dE}
这题逆向的一个小技巧:
可以看到这题包含很多很多的函数,所以这是个静态链接的程序,因为有很多库函数,我们不可能一个个点进去看,这里冠成大佬讲了一个技巧就是,通过查看main函数逻辑,写一个功能差不多的程序,然后利用ida的rizzo插件,进行模糊匹配,将符号导入dump下来的文件的database,然后大部分函数都会有正确的函数名了
gdb调试小技巧:
catch syscall 捕获程序的系统调用
catch syscall ptrace 捕获ptrace系统调用
set eax=0 设置eax 的值为0
通过设置 eax的值为0可以跳过ptrace系统调用
recall 回溯,只用在静态链接时有用
reverse continue 返回上一个断点
simplecheck:
这是一道android逆向,这是我第一次做android逆向题,虽然很简单,但是做出来就很开心
做android逆向需要了解一些前置知识
推荐看这一篇blog
了解完前置知识后就开始做题,我先将apk文件解压获得classes.dex文件
然后通过dex2jar工具将dex文件反编译得到jar包
这个要使用命令行
通过命令 ./d2j-dex2jar.bat classes.dex --force to overwrite 获得反编译的jar文件包
然后用 jd-gui-window查看反编译的java代码
定位到关键代码,a类的一个函数,查看这个a函数做了什么
image.png只有当输入的字符串满足判断语句时,才返回true
对判断条件进行解密:
解密脚本:
#!/usr/bin/env python
# -*- coding:UTF-8 -*-
a = [0, 146527998, 205327308, 94243885, 138810487, 408218567, 77866117, 71548549, 563255818, 559010506, 449018203, 576200653, 307283021, 467607947, 314806739, 341420795, 341420795, 469998524, 417733494, 342206934, 392460324, 382290309, 185532945, 364788505, 210058699, 198137551, 360748557, 440064477, 319861317, 676258995, 389214123, 829768461, 534844356, 427514172, 864054312 ];
b = [13710, 46393, 49151, 36900, 59564, 35883, 3517, 52957, 1509, 61207, 63274, 27694, 20932, 37997, 22069, 8438, 33995, 53298, 16908, 30902, 64602, 64028, 29629, 26537, 12026, 31610, 48639, 19968, 45654, 51972, 64956, 45293, 64752, 37108 ];
c = [38129, 57355, 22538, 47767, 8940, 4975, 27050, 56102, 21796, 41174, 63445, 53454, 28762, 59215, 16407, 64340, 37644, 59896, 41276, 25896, 27501, 38944, 37039, 38213, 61842, 43497, 9221, 9879, 14436, 60468, 19926, 47198, 8406, 64666 ];
d = [0, -341994984, -370404060, -257581614, -494024809, -135267265, 54930974, -155841406, 540422378, -107286502, -128056922, 265261633, 275964257, 119059597, 202392013, 283676377, 126284124, -68971076, 261217574, 197555158, -12893337, -10293675, 93868075, 121661845, 167461231, 123220255, 221507, 258914772, 180963987, 107841171, 41609001, 276531381, 169983906, 276158562 ];
flag = [0]
flag_s=""
for i in range(len(c)):
for j in range(0x20,0xff):
if(a[i+1] == b[i]*j*j + c[i]*j + d[i]):
print "find one char %s"%chr(j)
flag.append(j)
flag_s+=chr(j)
else:
continue
print flag_s
最后跑出来flag是:flag{MAth_i&_GOOd_DON7_90V_7hInK?}
regular -- magic
函数调用约定出错 -> IDA -> option -> compiler -> Visual C
要从 scanf 开始分析,跟踪输入流
RC4加密
setjmp longjmp 的概念
在setjmp()函数中,将setjmp()函数的返回地址以及其他一些寄存器存到jmp_buf中;而在longjmp函数中,将jmp_buf中保存的"setjmp()函数的返回地址"作为longjmp()函数自己的返回地址。于是执行ret指令之后,longjmp()函数返回到“调用setjmp()函数”处(准确来说是“调用setjmp()函数”的下一条指令的地址),并通过eax传回返回值。
题目自己实现指令集
非常规逆向:
特点:指令格式,架构不限定
可能包含的种类:
- lua/python/java/lua-jit/haskell/applescript/js/solidity 以太网智能合约
- firmware/raw bin etc
- chip8 、 avr、demency、risc-v etc....
做非常规题要搜索的工具:
find tools:
- binary parser 二进制分析程序
- disassembler 反汇编器
- tracer
- debugger 一般情况不会有
- decompiler 一般都不回有 看天意
find binary parser:
- google 大法
- 分析未知的二进制文件格式
- firmware:
先找基地址,然后找符号表 - 其他未知的二进制文件格式:
使用strings或者binwalk查看文件是否包含什么特征字符串或者是有没包含其他东东
寻找任何有用的线索
使用 IDA/radare2/binary ninja interface 或者使用ida loader
find Disassembler:
- google "xxxx disassembler/xxx IDA etc"
- 人肉反编译器
- IDA Pro/radare2/bianry.ninja interface
find tracer and debugger:
- tracer
尝试搜索官方 tracer - debugger
gdb-multian/qemu/emulator/trace replay
然后开始常规的逆向
pwn题的逆向分析策略:
首先必须熟悉常见的的漏洞
- 缓存区溢出
- 整数溢出
- 竞态条件
- etc
熟悉完常见的漏洞后,要了解一些漏洞挖掘的逆向技巧
- 关键数据结构的分析,还原结构体,接口,类等
- 控制流分析:理清程序的执行逻辑,基本要做到从反汇编代码到源码的还原
- 数据流分析,搞清数据的流向
漏洞挖掘的分析策略:
- 目标文件较小时,争取做到整个程序从返汇编代码到接近源码级别的还原
- 目标文件较大时,跟着数据流走,理清数据流经过的控制流
控制流分析:
- 目的是为了理清程序的逻辑,对于规模较小的目标文件,选择逆向整个文件
- 常用方法: 代码走查、字符串交叉引用、API引用
代码识别:
- 熟悉产常见的数据结构、算法在目标文件长什么样
- 链表、树、图、堆、各种加密算法
- 逆向是门经验活,多逆就会有体会
- 善用标记,标记结构体、变量名、变量类型
- F5不是万能的,当感到代码诡异时,要从汇编代码的层次分析
- 熟悉各类漏洞
网友评论