今天看啥  ›  专栏  ›  dog250

隐藏与篡改Linux命令行参数

dog250  · CSDN  ·  · 2021-04-03 10:17

如果一个程序的命令行是一个password之类的不便展示的字符串,如何不让ps打印出来呢?

ps是从/proc/$pid/cmdline里拿的命令行,而/proc/$pid/cmdline则是在内核空间解析用户程序的stack区域获取的数据,那么答案很简单,只需要覆盖掉这个区域即可,下面是个示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
	char orig[16];

	// 获取stack上的命令行
	strcpy(orig, argv[1]);
	// 获取命令行之后第一时间覆盖stack上的命令行
	strcpy(argv[1], "skinshoe");
	getchar();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如果应用程序不可修改代码重新编译,有没有什么统一的办法呢?当然有,用LD_PRELOAD很方便:

// inject.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int (*_main) (int, char * *, char * *);
static int pixie_main(int argc, char **argv, char **env)
{
	char tmp[16];
	strcpy(tmp, argv[1]);
	strncpy(argv[1], "pixie", strlen(argv[1]));
	argv[1] = tmp;
	return _main(argc, argv, env);
}

int (*orig_start_main)(int (*main)(int, char **, char **),
	    int argc,
	    char **argv,
	    void (*init) (void),
	    void (*fini) (void),
	    void (*_fini) (void),
	    void (*stack_end));


int __libc_start_main(int (*main)(int, char **, char **),
		     int argc, char **argv,
		     void (*init)(void),
		     void (*fini)(void),
		     void (*_fini)(void),
		     void (*stack_end))
{
	orig_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
	_main = main;
	return orig_start_main(pixie_main, argc, argv, init, fini, _fini, stack_end);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

编译之:

gcc -O2 -fPIC -shared -o libinject.so inject.c -ldl
  • 1
  • 1

下面是一个“不能改的现有程序”:

// demo.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
	printf("%s\n", argv[1]);
	getchar();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

用LD_PRELOAD执行之:

LD_PRELOAD=./libinject.so ./demo 12345
  • 1
  • 1

此时,demo程序打印的依然是12345,然后ps看到的就是pixie了。

把LD_PRELOAD部署到路径里就好了。这是劫库的标准手法。

事事都是双刃剑,能做好事就能做坏事,用上面的把戏其实是可以任意修改任意程序的命令行的:

int (*_main) (int, char * *, char * *);
static int pixie_main(int argc, char **argv, char **env)
{
	argv[1] = "pixie";
	return _main(argc, argv, env);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

试试看:

root@zhaoya-VirtualBox:~# LD_PRELOAD=./libinject.so ls -a
ls: cannot access 'pixie': No such file or directory
root@zhaoya-VirtualBox:~# LD_PRELOAD=./libinject.so /bin/echo hello
pixie
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

浙江温州皮鞋湿,下雨进水不会胖。




原文地址:访问原文地址
快照地址: 访问文章快照