Well, you can solve this issue by doing a syscall hook in the sys_ioctl.
The new sys_ioctl function must have the same prototype and should do the following:
(1) call the original sys_ioctl passing its own parameters, and save the return value;
(2) check if the "cmd" argument is equal to HDIO_GET_IDENTITY, if it is, then we need to manipulate the hd_driveid structure data, otherwise, jumps to (4);
(3) Store the fake s/n in the serial_no member from the hd_driveid structure;
(4) return the saved return value from the original sys_ioctl call;
Well, If you want to accomplish it under kernel 2.6.x, you'll face other problem:
- the sys_call_table isn't exported at this version;
To solve this issue, you need to calcule the sys_call_table address.
You can do that traversing the memory from the loops_per_jiffy address to boot_cpu_data address, since the sys_call_table is located between these two. To match the correct address, you need to compare the address you've started with and is using in the loop, with some syscall address. e.g.:
unsigned long **find_syscall_table(void) {
unsigned long ptr;
extern int loops_per_jiffy;
extern int boot_cpu_data;
for (ptr = (unsigned long)&loops_per_jiffy; ptr < (unsigned long)&boot_cpu_data; ptr += sizeof(void *)) {
unsigned long *p = (unsigned long *)ptr;
if (ptr[__NR_close] == (unsigned long)sys_close) {
printk(KERN_INFO "syscall table base found at %p", (unsigned long **)p);
return (unsigned long **)p;
}
}
return NULL;
}
sys_ioctl hook
Well, you can solve this issue by doing a syscall hook in the sys_ioctl.
The new sys_ioctl function must have the same prototype and should do the following:
(1) call the original sys_ioctl passing its own parameters, and save the return value;
(2) check if the "cmd" argument is equal to HDIO_GET_IDENTITY, if it is, then we need to manipulate the hd_driveid structure data, otherwise, jumps to (4);
(3) Store the fake s/n in the serial_no member from the hd_driveid structure;
(4) return the saved return value from the original sys_ioctl call;
Well, If you want to accomplish it under kernel 2.6.x, you'll face other problem:
- the sys_call_table isn't exported at this version;
To solve this issue, you need to calcule the sys_call_table address.
You can do that traversing the memory from the loops_per_jiffy address to boot_cpu_data address, since the sys_call_table is located between these two. To match the correct address, you need to compare the address you've started with and is using in the loop, with some syscall address. e.g.:
unsigned long **find_syscall_table(void) {
unsigned long ptr;
extern int loops_per_jiffy;
extern int boot_cpu_data;
for (ptr = (unsigned long)&loops_per_jiffy; ptr < (unsigned long)&boot_cpu_data; ptr += sizeof(void *)) {
unsigned long *p = (unsigned long *)ptr;
if (ptr[__NR_close] == (unsigned long)sys_close) {
printk(KERN_INFO "syscall table base found at %p", (unsigned long **)p);
return (unsigned long **)p;
}
}
return NULL;
}