/* kmem guard v0.1 this source protects and eventually repairs the syscalltable using /dev/kmem tested on Linux 2.6.7 vl4d@spine-group.org */ #include #include #include #include #include #include #define KMEM "/dev/kmem" #define BUF 128 #define ASM_SCTCALL "\xff\x14\x85" #define NR_syscalls 284 #define SCT_BUF (4*NR_syscalls) struct { unsigned short limit; unsigned int base; } __attribute__ ((packed)) idtr; /*this last one prevent gcc from padding struct members*/ struct { unsigned short off1; unsigned short sel; unsigned char none,flags; unsigned short off2; } __attribute__ ((packed)) idt; /* read data from kmem */ static inline int rkm(int fd, int offset, void *buf, int size) { if (lseek(fd, offset, 0) != offset) return 0; if (read(fd, buf, size) != size) return 0; return size; } /* write data to kmem */ static inline int wkm(int fd, int offset, void *buf, int size) { if (lseek(fd, offset, 0) != offset) return 0; if (write(fd, buf, size) != size) return 0; return size; } /* read int from kmem */ static inline int rkml(int fd, int offset, ulong *buf) { return rkm(fd, offset, buf, sizeof(ulong)); } /* write int to kmem */ static inline int wkml(int fd, int offset, ulong buf) { return wkm(fd, offset, &buf, sizeof(ulong)); } /* reads sct_addr from int 0x80 dispatch return sct_addr or -1 (error) */ int get_sct_addr(int kmem, int sysoff) { int sct_addr; char sct_code[BUF], *sct_p; if(!(rkm(kmem, sysoff, &sct_code, BUF))){ printf("unable to read kmem at 0x%X\n", sysoff); return -1; } sct_p = (char *)memmem(sct_code, BUF, ASM_SCTCALL, 3); sct_addr = *(unsigned *)(sct_p+3); return sct_addr; } int guard_kmem(int kmem, ulong safe_sct[], int sct_addr, int sysoff){ int i, *p, *p1; ulong tmp_syscall, tmp_sct_addr; if(!(rkml(kmem, sysoff, &tmp_sct_addr))) return -1; tmp_sct_addr = get_sct_addr(kmem, sysoff); if(tmp_sct_addr != sct_addr){ printf("WARNING!! Syscall Table should be in 0x%x instead of 0x%x! reboot asap!", sct_addr, tmp_sct_addr); return -1; } for(i = 0; i < NR_syscalls; i++){ if(!(rkml(kmem, (sct_addr+i*4), &tmp_syscall))) return -1; if(safe_sct[i] != tmp_syscall){ printf("WARNING!!! Syscall %i has been modified!" " 0x%x should be 0x%x\n", i, tmp_syscall, safe_sct[i]); if(!(wkml(kmem, (sct_addr+i*4), safe_sct[i]))) return -1; printf("syscall table restored!\n"); } } return 1; } int main(int argc, char **argv) { int kmem, sysoff, sct_addr, i; ulong safe_sct[NR_syscalls]; char sct_code[BUF], *sct_p; __asm__("sidt %0" : "=m"(idtr)); if((kmem = open(KMEM, O_RDWR)) == -1){ perror("open"); return 1; } if(!(rkm(kmem, (idtr.base+0x80*8), &idt, sizeof(idt)))){ printf("unable to read kmem at 0x%X\n", idtr.base); goto out; } sysoff = (idt.off2 << 16) | idt.off1; sct_addr = get_sct_addr(kmem, sysoff); printf("IDT at 0x%X\n" "SCT at 0x%X\n", idtr.base, sct_addr); for(i = 0; i < NR_syscalls; i++){ if(!rkml(kmem, (sct_addr+i*4), &safe_sct[i])){ printf("unable to read kmem at 0x%X", (sct_addr+i*4)); goto out; } } while(1){ if(guard_kmem(kmem, safe_sct, sct_addr, sysoff) == -1){ printf("unable to guard kmem\n"); goto out; } sleep(1); } out: close(kmem); return 0; }