re入门小题
IDA pro 7.7 全插件版,Lazy IDA为无名侠的版本。
IDA配置看IDA篇。
题目源自b站无名侠
默认有C语言,汇编和python基础
1. base64变表
base64编码原理
类似于进制转换,256->64进制
数据取每6bit->v(0-64)->编码表取出下标v对应的字符
下载T5.exe,ida打开,左栏ctrl+F
搜索main相关函数。
快捷键N
改一波名称
逻辑:异或->base64->比较字符串
跟踪sub_455A94
,找到sub_45A3F0
函数
跟踪off_529000
,其存放一个字符串地址的偏移量,继续跟踪
标准编码表
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
魔改之后的编码表
ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/
只需将魔改之后的编码对应到标准编码表的相同位置,之后再正常解码就行。(比如Z对应到A)
import base64
import time
t1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
t2="ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/"
c='Wj1gWE9xPSGUQ0KCPCGET09WR1qSzZ'
flag=''
for i in c:
flag+=t1[t2.index(i)]
flag=bytearray(base64.b64decode(flag+"=="))
for i in range(len(flag)):
flag[i]^=i
print(bytes(flag))
#b'flag{YOU_FIND_IT_HAHA}'
2. IDA动态调试
ida打开T6.exe
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t i; // [esp+190h] [ebp-340h]
char Str2[264]; // [esp+3A4h] [ebp-12Ch] BYREF
char Str1[32]; // [esp+4ACh] [ebp-24h] BYREF
qmemcpy(Str1, &unk_50DE50, 28u);//内存复制28位
printf("[6] Hi CTFer,Input your flag:");
scanf("%s", Str2);
for ( i = 0; i < j__strlen(Str1); ++i )
Str1[i] = ((i + 1) ^ Str1[i]) - i;
if ( !j__strcmp(Str1, Str2) )
printf("you are right\n");
else
printf("you are wrong\n");
return 0;
}
F2打断点,debugger选择local windows debugger,F9开启调试
输入12345678,在出现的汇编页面F5出伪代码。
跟踪Str1
点击字符串开头F,按快捷键A,将其解析成字符串。
或者选中一片内存,右键->convert->convert to python list(Byte)
,alt+0
查看结果
a2=[0x46, 0x6C, 0x61, 0x67, 0x7B, 0x54, 0x68, 0x69, 0x73, 0x5F, 0x49, 0x53, 0x5F, 0x54, 0x37, 0x5F, 0x44, 0x45, 0x42, 0x55, 0x47, 0x5F, 0x45, 0x41, 0x53, 0x59, 0x7D]
print(bytes(a2))
Flag{This_IS_T7_DEBUG_EASY}
3. 动态调试解RC4
流密码RC4加密解密是同一个算法
ida打开rc4.exe,搜main函数,改一波名。
观察到sub_FEF057是一个反调试函数且只执行一次,接收用户输入44个字符。
v7要与input最后的值相同。
直接运行rc4.exe,此时反调试函数已执行,在下图位置打断点。
debugger->attach to process,选择rc4的进程,以附加形式调试正在运行的程序
复制上去,F9运行,跟踪一波input的值(可以shift+F12),记录地址,再F9到第二个断点,此时RC4已完成,查看input的值
867DB6A7C7741F7EF97D8DF3295498D5E9B4B8895B620FC958902BD01E431A94C78A253280FD61950893EBA6
可以在运行到第一个断点时,将input对应的内存右键->paste data
成上面的值来验证RC4加密解密算法为同一个。
跟踪v7的值
E415C4EDA62F5610BB13EBAD7556C7BBBBE9B9CC023A509F369069BE7C4244CAC6D4245CD2B924C11893B3EA
同理,在第一个断点通过paste data,再F9运行到第二个断点,可以看到RC4之后的值
SYC{Pjx_s_Wom3n_cl0thing_1s_S0oo0o0_cute!1i}
4. IDA代码修复与数组识别
打开T7.exe
锁定main函数,它启动了一个定时器来反调试。
if ( sub_401000(Str, "flag{") != Str || Source[32] != '}' )
可以看出Str与Source其实是一个数组,快捷键Y修改Str的长度为52。
跟踪sub_401270,它的返回值未被接收,故快捷键Y改函数返回值类型为void。
*(_BYTE *)(a3 + *(_DWORD *)(a1 + 4 * v4)) = a2[v4];
之中的a3应该修改为char *
类型来指向一个数组,其中的a1应当为指向4字节(DWORD)的指针int *
。
改完后,代码变清晰,a3作为输出,与输入a2存在映射关系。
同理,修改sub_4011F0,sub_401360的返回值类型为void
跟踪sub_4011F0的dword_404040,右键->array将其转换为数组合,
此时可得到整个代码的主要逻辑:取flag{}
中间的值->异或->映射->比较字符串
import base64
import time
a23=bytearray(b"23gjf13au98hk3a1090zp8qjs41h39jp")
a1=[0x00000004, 0x0000000F, 0x0000000B, 0x0000001E, 0x0000000E, 0x00000014, 0x0000001F, 0x00000009, 0x00000017, 0x00000002, 0x00000019, 0x0000001C, 0x00000012, 0x00000010, 0x00000000, 0x00000008, 0x00000011, 0x00000001, 0x00000015, 0x00000003, 0x0000000A, 0x0000001D, 0x0000000C, 0x00000016, 0x00000018, 0x0000000D, 0x0000001B, 0x00000005, 0x00000007, 0x00000006, 0x00000013, 0x0000001A]
a2=[0]*32
bt_404040=[0x00000053, 0x00000045, 0x0000005C, 0x0000001E, 0x00000050, 0x00000013, 0x0000002F, 0x00000078, 0x00000004, 0x00000053, 0x00000058, 0x0000004A, 0x00000043, 0x00000001, 0x00000041, 0x0000002A, 0x00000008, 0x00000040, 0x00000067, 0x0000002F, 0x0000000C, 0x0000004A, 0x00000012, 0x0000002E, 0x00000041, 0x0000006C, 0x00000005, 0x00000054, 0x00000040, 0x00000012, 0x0000005B, 0x0000004F]
v4=0
while (v4<32):
a2[v4]=a23[a1[v4]]
v4+=1
for i in range(32):
a2[i]^=bt_404040[i]
print(b"flag{"+bytes(a2)+b"}")
#b'flag{5t4t1c_An4lys1s_1s_E4sy_2_me!!!~}'
5. UPX脱壳
upx是一种开源的压缩壳软件
加壳:upx a1.exe
脱壳:upx -d a1.exe (很多时候不管用)
手动脱壳目标
- 找到程序入口点(OEP)
- 在原始程序入口地址处设置硬件断点(硬件断点不会修改程序)
ida64打开helloupx11文件,发现其为elf文件,不能在windows运行,故拖入kali虚拟机
ls -al
chmod 777 ./helloupx11 添加可执行权限
ida查看一下字符串,可以看到是upx加壳
我们需要用到ida运程调试服务器。在IDA Pro 7.7.220118 SP1\dbgsrv
目录下有个linux_server64,将其拖入kali中。
./linux_ser* 启动监听
ifconfig 查看虚拟机ip地址
ida选择remote linux debugger,并输入虚拟机ip,如果端口占用则ps
查看进程id再kill -9 PID
杀进程
F2在开头打个软件断点,然后开始调试,F4执行到retn按F7,一直跟踪直到看到如下内存(要转成code才看得到)。
跟踪unk_401D55,按c解析成代码,再按p创建函数,再按F5查看伪代码
辨识一波
qword_4190E8[355] -> printf
sub_401190 -> strlen
sub_401130 -> strcmp
跟踪aFlagBffab77df5,看到flag为flag{bffab77df5cea353e2325bb4437c3d0b}
。
硬件断点
在401D55的endbr64处F2,再右键->edit breakpoint,点上hardware,使其成为硬件断点。
重新开启调试,跟踪到硬件断点处,按U取消定义,选中一片内存按C,按P,按F5看逻辑。