open 共享 linux,Linux 共享库注入后门

LINUX共享库

类似Windows系统中的动态链接库,Linux中也有相应的共享库用以支持代码的复用。Windows中为*.dll,而Linux中为*.so。下 面详细介绍如何创建、使用Linux的共享库。

一个例子:

#include

int sayhello( void )

{

printf("hello form sayhello function!/n");

return 0;

}

void saysomething(char * str)

{

printf("%s/n",str);

}

用下面的命令可以生成共享库

# gcc -fpic -shared sayhello.c -o libsay.so

解释:-f 后面跟一些编译选项,PIC 是 其中一种,表示生成位置无关代码(Position Independent Code)

实现方法

步骤1 — 关联进程

简单的调用ptrace(PTRACE_ATTACH,…)即可以关联到目标进程,但此后我们还需调用waitpid()函数等待目标进程暂停,以便我们进行后续操作。详见中给出的ptrace_attach()函数。

步骤2 — 发现_dl_open

通过遍历动态连接器使用的link_map结构及其指向的相关链表,我们可以完成_dl_open的符号解析工作,关于通过link_map解析符号在phrack59包的p59_08(见参考文献)中有详细的描述。

步骤3 — 装载.so

由于在2中我们已经找到_dl_open的地址,所以我们只需将此函数使用的参数添入相应的寄存器,并将进程的eip指向_dl_open即可,在此过程中还需做一些其它操作,具体内容见中的call_dl_open和ptrace_call函数。

步骤4 — 函数重定向

我们需要做的仅仅是找到相关的函数地址,用新函数替换旧函数,并将旧函数的地址保存。其中涉及到了PLT和RELOCATION,关于它们的详细内容你应该看ELF规范中的介绍,在中的函数中有PLT和RELOCATION的相关操作,而且在最后的例子中,我们将实现函数重定向。关于函数重定向,相关资料很多,这里不再多介绍。

步骤5 — 脱离进程

简单的调用ptrace(PTRACE_DETACH,…)可以脱离目标进程。

目标进程调试函数

在linux中,如果我们要调试一个进程,可以使用ptrace API函数,为了使用起来更方便,我们需要对它进行一些功能上的封装。

在p59_08中作者给出了一些对ptrace进行封装的函数,但是那太少了,在下面我给出了更多的函数,这足够我们使用了。要注意在这些函数中我并未进行太多的错误检测,但做为一个例子使用,它已经能很好的工作了,在最后的例子中你将能看到这一点

/* 关联到进程 */

void ptrace_attach(int pid)

{

if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {

perror("ptrace_attach");

exit(-1);

}

waitpid(pid, NULL, WUNTRACED);

ptrace_readreg(pid, &oldregs);

}

/* 进程继续 */

void ptrace_cont(int pid)

{

int stat;

if(ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {

perror("ptrace_cont");

exit(-1);

}

while(!WIFSTOPPED(stat))

waitpid(pid, &stat, WNOHANG);

}

/* 脱离进程 */

void ptrace_detach(int pid)

{

ptrace_writereg(pid, &oldregs);

if(ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {

perror("ptrace_detach");

exit(-1);

}

}

/* 写指定进程地址 */

void ptrace_write(int pid, unsigned long addr, void *vptr, int len)

{

int count;

long word;

count = 0;

while(count < len) {

memcpy(&word, vptr + count, sizeof(word));

word = ptrace(PTRACE_POKETEXT, pid, addr + count, word);

count += 4;

if(errno != 0)

printf("ptrace_write failed\t %ld\n", addr + count);

}

}

/* 读指定进程 */

void ptrace_read(int pid, unsigned long addr, void *vptr, int len)

{

int i,count;

long word;

unsigned long *ptr = (unsigned long *)vptr;

i = count = 0;

while (count < len) {

word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);

count += 4;

ptr[i++] = word;

}

}

/*

在进程指定地址读一个字符串

*/

char * ptrace_readstr(int pid, unsigned long addr)

{

char *str = (char *) malloc(64);

int i,count;

long word;

char *pa;

i = count = 0;

pa = (char *)&word;

while(i <= 60) {

word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL);

count += 4;

if (pa[0] == '\0') {

str[i] = '\0';

break;

}

else

str[i++] = pa[0];

if (pa[1] == '\0') {

str[i] = '\0';

break;

}

else

str[i++] = pa[1];

if (pa[2] == '\0') {

str[i] = '\0';

break;

}

else

str[i++] = pa[2];

if (pa[3] == '\0') {

str[i] = '\0';

break;

}

else

str[i++] = pa[3];

}

return str;

}

/* 读进程寄存器 */

void ptrace_readreg(int pid, struct user_regs_struct *regs)

{

if(ptrace(PTRACE_GETREGS, pid, NULL, regs))

printf("*** ptrace_readreg error ***\n");

}

/* 写进程寄存器 */

void ptrace_writereg(int pid, struct user_regs_struct *regs)

{

if(ptrace(PTRACE_SETREGS, pid, NULL, regs))

printf("*** ptrace_writereg error ***\n");

}

/*

将指定数据压入进程堆栈并返回堆栈指针

*/

void * ptrace_push(int pid, void *paddr, int size)

{

unsigned long esp;

struct user_regs_struct regs;

ptrace_readreg(pid, &regs);

esp = regs.esp;

esp -= size;

esp = esp - esp % 4;

regs.esp = esp;

ptrace_writereg(pid, &regs);

ptrace_write(pid, esp, paddr, size);

return (void *)esp;

}

/*

在进程内调用指定地址的函数

*/

void ptrace_call(int pid, unsigned long addr)

{

void *pc;

struct user_regs_struct regs;

int stat;

void *pra;

pc = (void *) 0x41414140;

pra = ptrace_push(pid, &pc, sizeof(pc));

ptrace_readreg(pid, &regs);

regs.eip = addr;

ptrace_writereg(pid, &regs);

ptrace_cont(pid);

while(!WIFSIGNALED(stat))

waitpid(pid, &stat, WNOHANG);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值