LD_PRELOAD加载动态链接库与gdb调试

0,前言

本文假设你对Linux运行应用程序有一定了解或者已经阅读过上一篇文章关于这方面的讲述。

1,背景

由于工作原因,需要了解LD_PRELOAD相关知识,在网络上搜索到一篇关于这方面知识较为全面的文章GDB调试LD_PRELOAD动态链接库(自己也对这篇文章做了些补充并被作者收纳,见该文章ID为gzhuflyer的评论),但总感觉作者讲解这方面知识跳动性有点大,很难实践理解,因此写下这篇文章。

2,示例程序运行

1,使用 rust 调用 C库例子进行分析。在linux系统中先准备rust环境,执行下面命令即可。

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

2,安装编译 syscall_intercept 库

sudo apt install cmake libcapstone-dev
git clone https://github.com/pmem/syscall_intercept.git
cd syscall_intercept
mkdir build
cd build && make && sudo make install

3,创建示例程序

cargo new ld-test --lib

ld-test目录结构如下
ld-test目录结构
将Cargo.toml 内容修改为:

[package]
name = "ld-test"
version = "0.1.0"
edition = "2021"

[dependencies]
ctor = "0.2.0"
libc = "0.2"
libsyscall-intercept = "0.1.1"

[lib]
name = "ld_test"
crate-type = ["dylib"]

将lib.rs内容修改为:

use std::cell::Cell;
#[macro_use]
extern crate ctor;
use libsyscall_intercept::{set_hook_fn,InterceptResult};


#[ctor]
fn init_preload() {
    unsafe { set_hook_fn(hook) };
}

extern "C" fn hook(
    num: i64,
    _a0: i64,
    _a1: i64,
    _a2: i64,
    _a3: i64,
    _a4: i64,
    _a5: i64,
    result: *mut i64,
) -> i32 {
    // detect and avoid recursive interception
    let _guard = match InterceptGuard::try_lock() {
        Some(g) => g,
        None => return InterceptResult::Forward as i32,
    };
    if num == libc::SYS_getdents64 || num == libc::SYS_getdents {
        unsafe {
            *result =  -libc::ENOTSUP as i64;
        } 
        return InterceptResult::Hook as i32;
    }
    InterceptResult::Forward as i32
}

thread_local! {
    static INTERCEPTED: Cell<bool> = Cell::new(false);
}

struct InterceptGuard;

impl InterceptGuard {
    fn try_lock() -> Option<Self> {
        INTERCEPTED.with(|x| {
            if x.get() {
                None
            } else {
                x.set(true);
                Some(InterceptGuard)
            }
        })
    }
}

impl Drop for InterceptGuard {
    fn drop(&mut self) {
        INTERCEPTED.with(|x| x.set(false));
    }
}

运行cargo b 命令编译生成动态库,并执行如下命令可以看到ls命令被拦截

gzhuflyer@frank-virtual-machine:~/workspace/ld-test$ LD_PRELOAD=./target/debug/libld_test.so ls
ls: 正在读取目录 '.': 不支持的操作

3, gdb调试 LD_PRELOAD动态库

1,下面展示 gdb 动态库调试截图
调试截图
gdb 运行程序之前,使用 set exec-wrapper env ‘LD_PRELOAD=/home/gzhuflyer/workspace/ld-test/target/debug/libld_test.so’ 设置环境变量,可以看到在执行main函数之前,会先调用执行动态库里面的hook函数,在这个示例中,使用rust ctor库中的宏,其作用和C语言 constructor 关键字类似。

4,写在最后

LD_PRELOAD在安全领域中也很常见,常用户函数和命令的执行,以及在操作系统中设置后门等操作,使用gdb调试时,在程序main函数打端点,并使用 info sharedlibrary,也可以查看到在执行main函数前已经加载了那些库,从而发现系统是否存在被恶意设置拦截等行为。至此,希望读者对LD_PRELOAD有更直观的了解。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gzhuflyer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值