UPX ELF Linux 手动动态脱壳(含一魔改壳实例)

#upx #packer
近期见到不少UPX魔改壳,需要走linux手脱,这里简单记录一个demo一个实例的手脱例子

魔改实例下载地址

我脱ELF的UPX壳主要有两条路径。
第一条是常规分析,跟踪到几个特征点就能判断当前脱壳到了哪一步。如特殊的jmp点,连续的几个循环和call调用,
第二条是入口点判断,ELF的UPX壳基本会走到call _dl_start、init、fini函数,或者说这是ELF程序函数头的特征,那么我们只需要调试到call _dl_start等初始化函数时,就能知道脱壳已完成了。
上述两条思路均有在下文中体现。

demo手脱

简单写一个测试程序

1
2
3
4
5
6
7
8
9
#include<stdio.h>
void hello(){
printf("here is hello!\n");
}
int main(){
hello();
printf("here is main!\n");
return 0;
}

普通编译指令

1
gcc test.c -o test

下载upx-linux版

1
2
wget https://github.com/upx/upx/releases/download/v4.2.4/upx-4.2.4-amd64_linux.tar.xz
tar -xvf upx-4.2.4-amd64_linux.tar.xz

alt text
这里同时测试一下-1和-9命令,对应两种压缩效果

1
2
./upx -1 ../test -o test_compress_faster
./upx -9 ../test -o test_compress_better

ida看看
函数结构差别不大
alt text
无其它段,只有load段
alt text
upx的-1~-9压缩级别不影响基本的解压缩方式,这里用-9 compress better做一个手动脱壳演示。
首先在start处下个断点
alt text一路f7,单步跟入后可发现如下地方:
alt text
upx linux的特点是,其会用到不少syscall来执行sys_open、sys_mmap等函数,以此来新建段、解密并执行。就像windows shellcode的VirtualAlloc+VirtualProtect一样
于是一直f7我们很容易看到:
新建段
alt text
这里我们还可以看一下段视图(ctrl+s)
调用之前:
alt text
调用之后(若是没显示是ida的问题,需要run一下才能刷新段视图,但其实段已经新建了):
alt text

修改段属性
alt text
紧跟着的jmp r13会跳转到新建的debug002段
alt text
依旧f7,f7之后会遇到三个循环体,这里没什么东西可以直接跳过
alt text
这个函数的下面还有一些函数
alt text
这些是会真正进行解密操作的函数,确定这一点是根据接下来的两种分析思路:
①一般这种小程序的入口点都是401000,我们可以在401000下硬件读、写断点或者执行断点,再或者接下来的几个call都f8,f8之后看看401000函数有没有变化.
如第一个callalt text
alt text
执行后:
alt text
可看到解密成功。
②UPX的linux版有一些固定的规律,比如
看到最底下的这一句
alt text
你一直f8到这里也差不多,总之到这里后继续跟进
可发现:
进入初始化函数了。
alt text
再一跳转
哟,start
alt text

魔改实例脱壳

alt text
这是一个4.01版本的魔改壳
alt text
需要注意的是,有的UPX打包的程序,其程序类型可能是DYN,ida动调时会提示:”Inputfile is a dynamic file。。。”然后不让你调试,这时候可以修改文件头信息从03->DYN改为02->EXECalt text
照样开头下断点
alt text
该程序运行起来时的段信息和我们正常的不太一样,于是就不太能像前面说的,对可能的开头代码下执行断点。
alt text
按照步骤执行到此处:
alt text
熟悉的地方
alt text

简易脱壳

1
2
3
4
5
6
7
8
9
10
11
from ida_bytes import *
from ida_idc import *
from ida_kernwin import *
from ida_dbg import *
from idaapi import *
start = 0
end = 0x692b
content = get_bytes(start, end-start)
f = open("unpack", "wb")
f.write(content)
f.close()

alt text
alt text