├── README.md ├── triton ├── README.md ├── memory_tracer.py ├── format_string_bug_analysis.py ├── use_after_free_bug_and_memory_leak_analysis.py └── code_coverage.py ├── lkm_samples ├── semaphore.c ├── cr0_wp_bit.c ├── Makefile ├── mutex.c ├── delete_module.c ├── thread.c ├── base_lkm.c ├── get_syscalls_table.c ├── give_creds.c ├── exec_process.c ├── timer.c ├── workqueues.c ├── proc_node.c ├── vma_flags.txt ├── hash_md5.c ├── hash_sha1.c ├── crypto_aes.c ├── vma.c ├── dev_node.c └── socket.c ├── CVE-2013-2164_fix.patch ├── fix_opcodes_sequence.py ├── syscalltable_hook_detection ├── hook_detected.py └── syscalltable_hook_detection.c ├── binary_analysis_with_ins_counts ├── ins_counts_bf.py └── inscount0.cpp ├── vtrace-dump_memory.py ├── vtrace-show_args_function.py ├── Simple-loop-detection-via-the-instruction-counter.cpp ├── Taint_analysis_and_pattern_matching_with_Pin ├── Example-1-Simple-taint-a-memory-area.cpp ├── Example-6-Pointer-without-check-detection.cpp ├── Example-2-Spread-the-taint-in-memory-and-registers.cpp ├── Example-3-Spread-the-taint-and-follow-your-data.cpp ├── Example-4-Obsolete-stack-frame-access-detection.cpp └── Example-5-Classical-Use-after-free-pattern-matching.cpp ├── elf-corruption-little-anti-debug.c ├── trace_linux_kernel_function.c ├── base_serv.c ├── metaSample.py ├── Pin-tool-InMemoryFuzzing.cpp ├── NDH_2013_CTF_unpack_kernel_3.7.10.patch ├── k1986.c └── PoC-Concolic-Execution-with-Pin-and-z3.cpp /README.md: -------------------------------------------------------------------------------- 1 | stuffz 2 | ====== 3 | 4 | A bunch of low-level stuffz. 5 | -------------------------------------------------------------------------------- /triton/README.md: -------------------------------------------------------------------------------- 1 | Backup of https://github.com/JonathanSalwan/Triton/tree/master/src/tools 2 | -------------------------------------------------------------------------------- /lkm_samples/semaphore.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | 5 | struct semaphore sem; 6 | 7 | up(&sem); 8 | down(&sem); 9 | 10 | -------------------------------------------------------------------------------- /lkm_samples/cr0_wp_bit.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | write_cr0(read_cr0() & (~0x10000)); /* disable bit WP */ 4 | write_cr0(read_cr0() | 0x10000); /* enable bit WP */ 5 | -------------------------------------------------------------------------------- /lkm_samples/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := your_module.o 2 | 3 | KDIR := /your/src/linux 4 | PWD := $(shell pwd) 5 | 6 | default: 7 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules 8 | -------------------------------------------------------------------------------- /lkm_samples/mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct mutex my_mutex; 4 | 5 | void foo(void) 6 | { 7 | mutex_lock(&my_mutex); 8 | /* ... */ 9 | mutex_unlock(&my_mutex); 10 | } 11 | -------------------------------------------------------------------------------- /lkm_samples/delete_module.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | static void delete_module(char *module_name) 4 | { 5 | struct module *task; 6 | 7 | task = find_module(module_name); 8 | if (task){ 9 | list_del(&task->list); 10 | return; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lkm_samples/thread.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | 5 | static int handler_thread(void *arg) 6 | { 7 | 8 | } 9 | 10 | static void foo(void) 11 | { 12 | kernel_thread(handler_thread, NULL, CLONE_KERNEL); /* thread 1 */ 13 | } 14 | -------------------------------------------------------------------------------- /lkm_samples/base_lkm.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int __init mod_init(void) 4 | { 5 | return 0; 6 | } 7 | 8 | static void __exit mod_exit(void) 9 | { 10 | } 11 | 12 | module_init(mod_init); 13 | module_exit(mod_exit); 14 | 15 | MODULE_AUTHOR("n/a"); 16 | MODULE_DESCRIPTION("n/a"); 17 | MODULE_LICENSE("GPL"); 18 | -------------------------------------------------------------------------------- /lkm_samples/get_syscalls_table.c: -------------------------------------------------------------------------------- 1 | static unsigned long *get_syscalls_table(void) 2 | { 3 | unsigned long *start; 4 | 5 | for (start = (unsigned long *)0xc0000000; start < (unsigned long *)0xffffffff; start++) 6 | if (start[__NR_close] == (unsigned long)sys_close){ 7 | return start; 8 | } 9 | return NULL; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /lkm_samples/give_creds.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | static void give_creds(void) 4 | { 5 | struct cred *new; 6 | 7 | new = prepare_creds(); /* Prepare a new set of credentials for modification */ 8 | new->euid = 0; /* Give root creds */ 9 | commit_creds(new); /* commit_creds - Install new credentials upon the current task */ 10 | } 11 | -------------------------------------------------------------------------------- /lkm_samples/exec_process.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | static int exec_process(void) 4 | { 5 | struct subprocess_info *sub_info; 6 | 7 | char *argv[] = {"/usr/bin/id", NULL}; 8 | static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL}; 9 | 10 | sub_info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC); 11 | if (sub_info == NULL) 12 | return -ENOMEM; 13 | return call_usermodehelper_exec(sub_info, UMH_WAIT_PROC); 14 | } 15 | -------------------------------------------------------------------------------- /CVE-2013-2164_fix.patch: -------------------------------------------------------------------------------- 1 | diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c 2 | index d620b44..8a3aff7 100644 3 | --- a/drivers/cdrom/cdrom.c 4 | +++ b/drivers/cdrom/cdrom.c 5 | @@ -2882,7 +2882,7 @@ static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, 6 | if (lba < 0) 7 | return -EINVAL; 8 | 9 | - cgc->buffer = kmalloc(blocksize, GFP_KERNEL); 10 | + cgc->buffer = kzalloc(blocksize, GFP_KERNEL); 11 | if (cgc->buffer == NULL) 12 | return -ENOMEM; 13 | -------------------------------------------------------------------------------- /lkm_samples/timer.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | 5 | #define TIME_SLEEP 30000 /* in msec */ 6 | 7 | static struct timer_list timer_s; 8 | 9 | static void timer_handler(unsigned long data) 10 | { 11 | printk("Timer handler !\n"); 12 | } 13 | 14 | static void foo(void) 15 | { 16 | setup_timer(&timer_s, timer_handler, 0); 17 | if (mod_timer(&timer_s, jiffies + msecs_to_jiffies(TIME_SLEEP))){ 18 | printk(KERN_INFO "Failed to set timer\n"); 19 | return -ECANCELED; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lkm_samples/workqueues.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static struct workqueue_struct *wq; 4 | 5 | static void func_handler(struct work_struct *w) 6 | { 7 | 8 | } 9 | static DECLARE_DELAYED_WORK(func, func_handler); 10 | 11 | static int __init hook_detection_init(void) 12 | { 13 | unsigned long onesec; 14 | 15 | wq = create_singlethread_workqueue("wq"); 16 | 17 | onesec = msecs_to_jiffies(1000); 18 | queue_delayed_work(wq, &func, onesec); 19 | } 20 | 21 | static void __exit hook_detection_exit(void) 22 | { 23 | if (wq) 24 | destroy_workqueue(wq); 25 | } 26 | -------------------------------------------------------------------------------- /fix_opcodes_sequence.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## By Jonathan Salwan - http://twitter.com/JonathanSalwan 5 | ## 6 | 7 | import sys 8 | 9 | if __name__ == "__main__": 10 | 11 | 12 | if len(sys.argv) < 3: 13 | print "Syntax : %s " %(sys.argv[0]) 14 | sys.exit(1) 15 | 16 | op = sys.argv[2].decode("hex") 17 | nop = "\x90" * len(op) 18 | 19 | fd = open(sys.argv[1], "r") 20 | raw = fd.read() 21 | fd.close() 22 | 23 | raw = raw.replace(op, nop) 24 | 25 | fd = open(sys.argv[1] + ".patched", "w") 26 | fd.write(raw) 27 | fd.close() 28 | 29 | print "Binary patched" 30 | 31 | sys.exit(0) 32 | 33 | -------------------------------------------------------------------------------- /lkm_samples/proc_node.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | #include 3 | 4 | static ssize_t handler_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) 5 | { 6 | 7 | } 8 | 9 | static ssize_t handler_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) 10 | { 11 | 12 | } 13 | 14 | static int create_proc_node(void) 15 | { 16 | struct proc_dir_entry *proc_entry; 17 | 18 | proc_entry = create_proc_entry("proc_name", 0666, NULL); 19 | if (proc_entry){ 20 | proc_entry->write_proc = handler_proc_write; 21 | proc_entry->read_proc = handler_proc_read; 22 | } 23 | return 0; 24 | } 25 | 26 | static void remove_proc_node(void) 27 | { 28 | remove_proc_entry("proc_name", NULL); 29 | } 30 | -------------------------------------------------------------------------------- /lkm_samples/vma_flags.txt: -------------------------------------------------------------------------------- 1 | VM_READ Pages can be read from 2 | VM_WRITE Pages can be written to 3 | VM_EXEC Pages can be executed 4 | VM_SHARED Pages are shared 5 | VM_MAYREAD The VM_READ flag can be set 6 | VM_MAYWRITE The VM_WRITE flag can be set 7 | VM_MAYEXEC The VM_EXEC flag can be set 8 | VM_MAYSHARE The VM_SHARE flag can be set 9 | VM_GROWSDOWN The area can grow downward 10 | VM_GROWSUP The area can grow upward 11 | VM_SHM The area is used for shared memory 12 | VM_DENYWRITE The area maps an unwritable file 13 | VM_EXECUTABLE The area maps an executable file 14 | VM_LOCKED The pages in this area are locked 15 | VM_IO The area maps a device's I/O space 16 | VM_SEQ_READ The pages seem to be accessed sequentially 17 | VM_RAND_READ The pages seem to be accessed randomly 18 | VM_DONTCOPY This area must not be copied on fork() 19 | VM_DONTEXPAND This area cannot grow via mremap() 20 | VM_RESERVED This area must not be swapped out 21 | VM_ACCOUNT This area is an accounted VM object 22 | VM_HUGETLB This area uses hugetlb pages 23 | VM_NONLINEAR This area is a nonlinear mapping 24 | -------------------------------------------------------------------------------- /lkm_samples/hash_md5.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | #include 5 | 6 | static void dump(char *hash_md5) 7 | { 8 | int i; 9 | 10 | for (i = 0; i < 16 ; i++){ 11 | printk("%02x", (unsigned char)hash_md5[i]); 12 | } 13 | printk("\n"); 14 | } 15 | 16 | int mod_init(void) 17 | { 18 | char hash_md5[16]; 19 | struct crypto_shash *md5; 20 | struct shash_desc *shash; 21 | 22 | md5 = crypto_alloc_shash("md5", 0, 0); 23 | if (IS_ERR(md5)) 24 | return -1; 25 | 26 | shash = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(md5), 27 | GFP_KERNEL); 28 | if (!shash) 29 | return -ENOMEM; 30 | 31 | shash->tfm = md5; 32 | shash->flags = 0; 33 | 34 | if (crypto_shash_init(shash)) 35 | return -1; 36 | 37 | if (crypto_shash_update(shash, "test", 4)) 38 | return -1; 39 | 40 | if (crypto_shash_final(shash, hash_md5)) 41 | return -1; 42 | 43 | kfree(shash); 44 | crypto_free_shash(md5); 45 | 46 | dump(hash_md5); 47 | 48 | return 0; 49 | } 50 | 51 | void mod_exit(void) 52 | { 53 | } 54 | 55 | module_init(mod_init); 56 | module_exit(mod_exit); 57 | 58 | MODULE_AUTHOR("n/a"); 59 | MODULE_DESCRIPTION("n/a"); 60 | MODULE_LICENSE("GPL"); 61 | -------------------------------------------------------------------------------- /lkm_samples/hash_sha1.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | #include 5 | 6 | static void dump(char *hash_sha1) 7 | { 8 | int i; 9 | 10 | for (i = 0; i < 20 ; i++){ 11 | printk("%02x", (unsigned char)hash_sha1[i]); 12 | } 13 | printk("\n"); 14 | } 15 | 16 | int mod_init(void) 17 | { 18 | char hash_sha1[20]; 19 | struct crypto_shash *sha1; 20 | struct shash_desc *shash; 21 | 22 | sha1 = crypto_alloc_shash("sha1", 0, 0); 23 | if (IS_ERR(sha1)) 24 | return -1; 25 | 26 | shash = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(sha1), 27 | GFP_KERNEL); 28 | if (!shash) 29 | return -ENOMEM; 30 | 31 | shash->tfm = sha1; 32 | shash->flags = 0; 33 | 34 | if (crypto_shash_init(shash)) 35 | return -1; 36 | 37 | if (crypto_shash_update(shash, "test", 4)) 38 | return -1; 39 | 40 | if (crypto_shash_final(shash, hash_sha1)) 41 | return -1; 42 | 43 | kfree(shash); 44 | crypto_free_shash(sha1); 45 | 46 | dump(hash_sha1); 47 | 48 | return 0; 49 | } 50 | 51 | void mod_exit(void) 52 | { 53 | } 54 | 55 | module_init(mod_init); 56 | module_exit(mod_exit); 57 | 58 | MODULE_AUTHOR("n/a"); 59 | MODULE_DESCRIPTION("n/a"); 60 | MODULE_LICENSE("GPL"); 61 | 62 | -------------------------------------------------------------------------------- /lkm_samples/crypto_aes.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | #include 5 | 6 | char pkey[] = "yourKey"; 7 | char plaintext[] = "Your clear text here. "; 8 | 9 | char crypted[512]; 10 | 11 | static void dump(char *str, char *ptr) 12 | { 13 | int i; 14 | 15 | printk("%s", str); 16 | for (i = 0 ; i < sizeof(plaintext) ; i++){ 17 | printk("%02x ", (unsigned char)ptr[i]); 18 | } 19 | printk("\n"); 20 | } 21 | 22 | int mod_init(void) 23 | { 24 | struct crypto_cipher *tfm; 25 | 26 | tfm = crypto_alloc_cipher("aes", 4, CRYPTO_ALG_ASYNC); 27 | if (!tfm) 28 | return -1; 29 | 30 | crypto_cipher_setkey(tfm, pkey, sizeof(pkey)); 31 | 32 | dump("PlainText:\t", plaintext); 33 | 34 | crypto_cipher_encrypt_one(tfm, &crypted[0], &plaintext[0]); 35 | crypto_cipher_encrypt_one(tfm, &crypted[16], &plaintext[16]); 36 | 37 | dump("Crypted:\t\t", crypted); 38 | 39 | crypto_cipher_decrypt_one(tfm, &crypted[0], &crypted[0]); 40 | crypto_cipher_decrypt_one(tfm, &crypted[16], &crypted[16]); 41 | 42 | dump("Uncrypted:\t", crypted); 43 | 44 | crypto_free_cipher(tfm); 45 | 46 | return 0; 47 | } 48 | 49 | void mod_exit(void) 50 | { 51 | } 52 | 53 | module_init(mod_init); 54 | module_exit(mod_exit); 55 | 56 | MODULE_AUTHOR("n/a"); 57 | MODULE_DESCRIPTION("n/a"); 58 | MODULE_LICENSE("GPL"); 59 | 60 | -------------------------------------------------------------------------------- /lkm_samples/vma.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static void func_vm_open(struct vm_area_struct *area) 14 | { 15 | printk(KERN_ALERT "vm open\n"); 16 | } 17 | 18 | static void func_vm_close(struct vm_area_struct *area) 19 | { 20 | printk(KERN_ALERT "vm close\n"); 21 | } 22 | 23 | static int func_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 24 | { 25 | printk(KERN_ALERT "vm fault at %p\n", vmf->virtual_address); 26 | return 0; 27 | } 28 | 29 | static const struct vm_operations_struct ralloc_vm_ops = { 30 | .open = func_vm_open, 31 | .close = func_vm_close, 32 | .fault = func_vm_fault, 33 | }; 34 | 35 | static unsigned long foo(void) 36 | { 37 | struct vm_area_struct *vma; 38 | unsigned long addr = 0; 39 | 40 | vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); 41 | if (vma == NULL) 42 | goto out; 43 | 44 | addr = 0x10000; 45 | INIT_LIST_HEAD(&vma->anon_vma_chain); 46 | vma->vm_mm = current->mm; 47 | vma->vm_start = addr; 48 | vma->vm_end = addr + 0x1000; 49 | vma->vm_ops = &ralloc_vm_ops; 50 | vma->vm_flags = VM_READ | VM_WRITE | VM_MIXEDMAP; 51 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 52 | vma->vm_pgoff = 0x10000 >> PAGE_SHIFT; 53 | insert_vm_struct(current->mm, vma); 54 | 55 | out: 56 | return addr; 57 | } 58 | -------------------------------------------------------------------------------- /syscalltable_hook_detection/hook_detected.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Copyright (C) 2013 - Jonathan Salwan - http://twitter.com/JonathanSalwan 5 | ## 6 | ## This program is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This program is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU General Public License 17 | ## along with this program. If not, see . 18 | ## 19 | 20 | import smtplib 21 | import sys 22 | 23 | RCPT_TO = 'mail_rcpt@gmail.com' 24 | GUSER = 'your_mail@gmail.com' 25 | GPWD = 'you_passwd' 26 | SMTP = 'smtp.gmail.com' 27 | 28 | if __name__ == "__main__": 29 | 30 | smtpserver = smtplib.SMTP(SMTP, 587) 31 | smtpserver.ehlo() 32 | smtpserver.starttls() 33 | smtpserver.ehlo 34 | smtpserver.login(GUSER, GPWD) 35 | 36 | msg = 'To: ' + RCPT_TO + '\n' 37 | msg += 'From: ' + GUSER + '\n' 38 | msg += 'Subject:Hook analyzer - Hook detected !\n\n' 39 | msg += 'Hook analyzer has detected a hook in syscall table ' 40 | msg += '(syscall %s).\n' %(sys.argv[1]) 41 | msg += 'The syscall was restored.\n\n' 42 | 43 | smtpserver.sendmail(GUSER, RCPT_TO, msg) 44 | smtpserver.close() 45 | 46 | sys.exit(0) 47 | -------------------------------------------------------------------------------- /binary_analysis_with_ins_counts/ins_counts_bf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Copyright (C) 2013 - Jonathan Salwan - http://twitter.com/JonathanSalwan 5 | ## 6 | ## This program is free software: you can redistribute it and/or modify 7 | ## it under the terms of the GNU General Public License as published by 8 | ## the Free Software Foundation, either version 3 of the License, or 9 | ## (at your option) any later version. 10 | ## 11 | ## This program is distributed in the hope that it will be useful, 12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ## GNU General Public License for more details. 15 | ## 16 | ## You should have received a copy of the GNU General Public License 17 | ## along with this program. If not, see . 18 | ## 19 | 20 | import sys 21 | import commands 22 | 23 | if __name__ == "__main__": 24 | 25 | if len(sys.argv) != 4: 26 | print "%s " 27 | sys.exit(-1) 28 | 29 | pwd = "_" * int(sys.argv[2]) 30 | base = 0x2e 31 | off = 0x00 32 | sav = 0x00 33 | 34 | while pwd.find('Good Password') == -1: 35 | pwd = pwd[:off] + chr(base) + pwd[off+1:]; 36 | cmd = "../pin -t ./inscount0.so -- %s '%s'; cat inscount.out" %(sys.argv[1], pwd) 37 | res = int(commands.getstatusoutput(cmd)[1].split("Count")[1]) 38 | print "insert('%s') = %d ins" %(pwd, res) 39 | if sav == 0x00: 40 | sav = res 41 | if res - sav > int(sys.argv[3]): 42 | off += 1 43 | if off >= len(pwd): 44 | break 45 | base = 0x2d 46 | sav = 0 47 | base += 1 48 | sav = res 49 | 50 | print "The password is %s" %(pwd) 51 | sys.exit(0) 52 | 53 | -------------------------------------------------------------------------------- /lkm_samples/dev_node.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static dev_t Dev; 10 | static struct cdev Cdev; 11 | static struct class *Class; 12 | 13 | static int device_open(struct inode *inode, struct file *file) 14 | { 15 | return 0; 16 | } 17 | 18 | static int device_release(struct inode *inode, struct file *file) 19 | { 20 | return 0; 21 | } 22 | 23 | static ssize_t device_read(struct file *filp, char *buffer, size_t length, 24 | loff_t * offset) 25 | { 26 | int bytes_read = 0; 27 | 28 | return bytes_read; 29 | } 30 | 31 | static ssize_t device_write(struct file *filp, const char *buff, size_t len, 32 | loff_t * off) 33 | { 34 | return 0; 35 | } 36 | 37 | static struct file_operations fops = { 38 | .owner = THIS_MODULE, 39 | .read = device_read, 40 | .write = device_write, 41 | .open = device_open, 42 | .release = device_release 43 | }; 44 | 45 | static int __init mod_init(void) 46 | { 47 | if (alloc_chrdev_region(&Dev, 0, 1, "chrDevName") < 0) 48 | goto out; 49 | 50 | if ((Class = class_create(THIS_MODULE, "charDrv")) == NULL) 51 | goto region; 52 | 53 | if (device_create(Class, NULL, Dev, NULL, "myDevice") == NULL) 54 | goto class; 55 | 56 | cdev_init(&Cdev, &fops); 57 | if (cdev_add(&Cdev, Dev, 1) == -1) 58 | goto device; 59 | 60 | return 0; 61 | 62 | device: 63 | device_destroy(Class, Dev); 64 | class: 65 | class_destroy(Class); 66 | region: 67 | unregister_chrdev_region(Dev, 1); 68 | out: 69 | return -1; 70 | } 71 | 72 | static void __exit mod_exit(void) 73 | { 74 | cdev_del(&Cdev); 75 | device_destroy(Class, Dev); 76 | class_destroy(Class); 77 | unregister_chrdev_region(Dev, 1); 78 | } 79 | 80 | module_init(mod_init); 81 | module_exit(mod_exit); 82 | 83 | MODULE_AUTHOR("n/a"); 84 | MODULE_DESCRIPTION("n/a"); 85 | MODULE_LICENSE("GPL"); 86 | 87 | -------------------------------------------------------------------------------- /vtrace-dump_memory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | # 4 | # vtrace-dump_memory.py - Dump memory from a breakpoint. 5 | # 6 | # Syntax : ./vtrace-dump_memory.py 7 | # Exemple: ./vtrace-dump_memory.py ./binary 0x8048438 0x08069322 256 8 | # 9 | # Copyright (C) 2012-06 Jonathan Salwan - http://www.twitter.com/jonathansalwan 10 | # 11 | # This program is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see . 23 | # 24 | 25 | import vtrace 26 | import vdb 27 | import sys 28 | import envi 29 | import struct 30 | from envi.archs.i386 import * 31 | 32 | def dump_memory(trace, memory, size): 33 | print "[+] Breakpoint at 0x%08x" %(trace.getRegister(REG_EIP)) 34 | try: 35 | dump = trace.readMemory(memory, size); 36 | except: 37 | print "[EE] Impossible to read from 0x%08x" %(memory) 38 | return 39 | try: 40 | fd = open("vtrace-memory.dump", "w") 41 | fd.write(dump) 42 | fd.close() 43 | print "[+] Dump successful" 44 | except: 45 | print "[EE] Impossible de save the dump file" 46 | return 47 | 48 | def main(binary, breakpoint, memory, size): 49 | trace = vtrace.getTrace() 50 | try: 51 | trace.execute(binary) 52 | except: 53 | print "[EE] No such file" 54 | try: 55 | trace.addBreakByAddr(breakpoint) 56 | except: 57 | print "[EE] Invalide addr %s" %(hex(breakpoint)) 58 | return 59 | trace.run() 60 | dump_memory(trace, memory, size) 61 | return (0) 62 | 63 | if __name__ == "__main__": 64 | if len(sys.argv) == 5: 65 | sys.exit(main(sys.argv[1], int(sys.argv[2], 16), int(sys.argv[3], 16), int(sys.argv[4]))) 66 | else: 67 | print "Usage: %s " %(sys.argv[0]) 68 | sys.exit(-1) 69 | 70 | -------------------------------------------------------------------------------- /lkm_samples/socket.c: -------------------------------------------------------------------------------- 1 | /* 3.2.0 */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static struct sockaddr_in _sin; 10 | static struct msghdr _msg; 11 | static struct iovec _iov; 12 | static struct socket *_sock; 13 | 14 | static uint32_t create_address(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4) 15 | { 16 | uint32_t addr = 0; 17 | 18 | addr += i1, addr <<= 8; 19 | addr += i2, addr <<= 8; 20 | addr += i3, addr <<= 8; 21 | addr += i4; 22 | 23 | return (addr); 24 | } 25 | 26 | static int connect(void) 27 | { 28 | int err; 29 | 30 | if (sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &_sock) < 0){ 31 | return -1; 32 | } 33 | 34 | memset(&_sin, 0, sizeof(_sin)); 35 | _sin.sin_family = AF_INET; 36 | _sin.sin_addr.s_addr = htonl(create_address(127, 0, 0, 1)); 37 | _sin.sin_port = htons(1234); 38 | 39 | err = _sock->ops->connect(_sock, (struct sockaddr*)&_sin, sizeof(_sin), O_RDWR); 40 | if (err < 0){ 41 | return -1; 42 | } 43 | return 0; 44 | } 45 | 46 | static void disconnect(void) 47 | { 48 | sock_release(_sock); 49 | } 50 | 51 | static int send_msg(char *msg, uint32_t len) 52 | { 53 | int ret; 54 | mm_segment_t oldfs; 55 | 56 | _msg.msg_name = 0; 57 | _msg.msg_namelen = 0; 58 | _msg.msg_iov = &_iov; 59 | _msg.msg_iovlen = 1; 60 | _msg.msg_control = NULL; 61 | _msg.msg_controllen = 0; 62 | _msg.msg_flags = MSG_DONTWAIT; 63 | 64 | _msg.msg_iov->iov_base = msg; 65 | _msg.msg_iov->iov_len = len; 66 | 67 | oldfs = get_fs(); 68 | set_fs(KERNEL_DS); 69 | ret = sock_sendmsg(_sock, &_msg, len); 70 | if (ret == -1) 71 | disconnect(); 72 | set_fs(oldfs); 73 | 74 | return ret; 75 | } 76 | 77 | static int recv_msg(char *buffer, uint32_t len) 78 | { 79 | int ret; 80 | mm_segment_t oldfs; 81 | 82 | _msg.msg_name = 0; 83 | _msg.msg_namelen = 0; 84 | _msg.msg_iov = &_iov; 85 | _msg.msg_iovlen = 1; 86 | _msg.msg_control = NULL; 87 | _msg.msg_controllen = 0; 88 | _msg.msg_flags = MSG_DONTWAIT; 89 | 90 | _msg.msg_iov->iov_base = buffer; 91 | _msg.msg_iov->iov_len = len; 92 | 93 | oldfs = get_fs(); 94 | set_fs(KERNEL_DS); 95 | ret = sock_recvmsg(_sock, &_msg, len, 0); 96 | if (ret == -1) 97 | disconnect(); 98 | set_fs(oldfs); 99 | 100 | return ret; 101 | } 102 | -------------------------------------------------------------------------------- /vtrace-show_args_function.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | # 4 | # vtrace-show_args_function.py - Script for vtrace API for display arguments function before call. 5 | # 6 | # Syntax : ./vtrace-show_args_function.py 7 | # Exemple: ./vtrace-show_args_function.py ./binary 0x8048438 2 8 | # 9 | # Copyright (C) 2012-06 Jonathan Salwan - http://www.twitter.com/jonathansalwan 10 | # 11 | # This program is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see . 23 | # 24 | 25 | import vtrace 26 | import vdb 27 | import sys 28 | import envi 29 | import struct 30 | from envi.archs.i386 import * 31 | 32 | def print_stack(trace, arg_number): 33 | n = 0 34 | esp = trace.getRegister(REG_ESP) 35 | print "[+] Breakpoint at 0x%08x" %(trace.getRegister(REG_EIP)) 36 | while n < arg_number: 37 | try: 38 | arg = trace.readMemory((esp+(n*4)), 4); 39 | except: 40 | print "[EE] Invalide ESP pointeur (0x%08x)" %(esp) 41 | return 42 | arg = struct.unpack(" " %(sys.argv[0]) 71 | sys.exit(-1) 72 | 73 | -------------------------------------------------------------------------------- /Simple-loop-detection-via-the-instruction-counter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - 2013-08-13 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Pin tool - Simple loop detection via the instruction counter. 8 | // Output: https://github.com/JonathanSalwan/stuffz/blob/master/output_loop_detection.txt 9 | 10 | #include "pin.H" 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define LOCKED 1 17 | #define UNLOCKED !LOCKED 18 | 19 | static UINT32 _lockAnalysis = !LOCKED; /* unlock -> without sym */ 20 | static UINT16 _tabAddr[0x10000]; 21 | static std::string _tabStr[0x10000]; 22 | 23 | INT32 Usage() 24 | { 25 | std::cerr << "Foo test" << std::endl; 26 | return -1; 27 | } 28 | 29 | VOID insCallBack(UINT64 insAddr, std::string insDis) 30 | { 31 | if (_lockAnalysis) 32 | return ; 33 | 34 | if (insAddr > 0x700000000000) 35 | return; 36 | 37 | if (_tabAddr[insAddr ^ 0x400000] == 0xffff) 38 | return; 39 | 40 | _tabAddr[insAddr ^ 0x400000] += 1; 41 | _tabStr[insAddr ^ 0x400000] = insDis; 42 | 43 | } 44 | 45 | VOID Instruction(INS ins, VOID *v) 46 | { 47 | INS_InsertCall( 48 | ins, IPOINT_BEFORE, (AFUNPTR)insCallBack, 49 | IARG_ADDRINT, INS_Address(ins), 50 | IARG_PTR, new string(INS_Disassemble(ins)), 51 | IARG_END); 52 | } 53 | 54 | VOID unlockAnalysis(void) 55 | { 56 | _lockAnalysis = UNLOCKED; 57 | } 58 | 59 | VOID lockAnalysis(void) 60 | { 61 | _lockAnalysis = LOCKED; 62 | } 63 | 64 | VOID Image(IMG img, VOID *v) 65 | { 66 | RTN mainRtn = RTN_FindByName(img, "main"); 67 | 68 | if (RTN_Valid(mainRtn)){ 69 | RTN_Open(mainRtn); 70 | RTN_InsertCall(mainRtn, IPOINT_BEFORE, (AFUNPTR)unlockAnalysis, IARG_END); 71 | RTN_InsertCall(mainRtn, IPOINT_AFTER, (AFUNPTR)lockAnalysis, IARG_END); 72 | RTN_Close(mainRtn); 73 | } 74 | } 75 | 76 | VOID Fini(INT32 code, VOID *v) 77 | { 78 | UINT32 i; 79 | 80 | std::cout << "Addr\tNumber\tDisass" << std::endl; 81 | for (i = 0; i < 0x10000; i++){ 82 | if (_tabAddr[i]) 83 | std::cout << std::hex << (0x400000 + i) << "\t" << std::dec << _tabAddr[i] << "\t" << _tabStr[i] << std::endl; 84 | } 85 | } 86 | 87 | int main(int argc, char *argv[]) 88 | { 89 | PIN_InitSymbols(); 90 | if(PIN_Init(argc, argv)){ 91 | return Usage(); 92 | } 93 | 94 | PIN_SetSyntaxIntel(); 95 | IMG_AddInstrumentFunction(Image, 0); 96 | INS_AddInstrumentFunction(Instruction, 0); 97 | PIN_AddFiniFunction(Fini, 0); 98 | PIN_StartProgram(); 99 | 100 | return 0; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /triton/memory_tracer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Triton tool to trace memory access. 5 | ## Jonathan Salwan - 2015-04-30 6 | ## 7 | ## Description: 8 | ## ------------ 9 | ## 10 | ## This tool is used to trace all memory access. With this tool, you know 11 | ## which instruction read or write in memory, where it reads/writes, 12 | ## the access' size and the value. May be useful to track quickly some 13 | ## specific data. 14 | ## 15 | ## Output: 16 | ## ------- 17 | ## 18 | ## $ ./triton ./src/tools/memory_tracer.py ./src/samples/crackmes/crackme_xor A 19 | ## [...] 20 | ## [08] 0x00007f27d55157f0: mov rbx, qword ptr [r13] 0x00007ffe99e386b8: 98 89 72 d5 27 7f 00 00 (0x7f27d5728998) 21 | ## [01] 0x00007f27d55157f4: movzx eax, byte ptr [rbx + 0x314] 0x00007f27d5728cac: 1d (0x1d) 22 | ## [01] 0x00007f27d5515802: mov byte ptr [rbx + 0x314], al 0x00007f27d5728cac: 1d (0x1d) 23 | ## [08] 0x00007f27d5515808: mov rax, qword ptr [rbx + 0x110] 0x00007f27d5728aa8: 00 00 00 00 00 00 00 00 (0x0) 24 | ## [08] 0x00007f27d5515890: mov rdx, qword ptr [rbx + 0xa8] 0x00007f27d5728a40: 00 00 00 00 00 00 00 00 (0x0) 25 | ## [04] 0x00007f27d5515865: mov esi, dword ptr [rbp - 0x34] 0x00007ffe99e386fc: 00 00 00 00 (0x0) 26 | ## [04] 0x00007f27d551586c: mov ecx, dword ptr [rip + 0x21252e] 0x00007f27d5727da0: 00 00 00 00 (0x0) 27 | ## [04] 0x00007f27d551587a: sub dword ptr [rbx + 0x310], 1 0x00007f27d5728ca8: 01 00 00 00 (0x1) 28 | ## [...] 29 | ## 30 | 31 | from triton import * 32 | from pintool import * 33 | 34 | 35 | def dump(instruction, operand): 36 | memoryAccess = operand.getAddress() 37 | memoryAccessSize = operand.getSize() 38 | 39 | a = str() 40 | d = '[%02d] 0x%016x: %s' %(memoryAccessSize, instruction.getAddress(), instruction.getDisassembly()) 41 | 42 | if checkReadAccess(memoryAccess) and checkReadAccess(memoryAccess+memoryAccessSize): 43 | a = '0x%016x:' %(memoryAccess) 44 | for i in range(memoryAccessSize): 45 | a += ' %02x' %(getCurrentMemoryValue(memoryAccess+i)) 46 | print '%s%s%s (%#x)' %(d, ' '*(70-len(d)), a, getCurrentMemoryValue(memoryAccess, memoryAccessSize)) 47 | 48 | return 49 | 50 | 51 | def before(instruction): 52 | for operand in instruction.getOperands(): 53 | if operand.getType() == OPERAND.MEM: 54 | dump(instruction, operand) 55 | return 56 | return 57 | 58 | 59 | if __name__ == '__main__': 60 | # Set architecture 61 | setArchitecture(ARCH.X86_64) 62 | 63 | # Start the symbolic analysis from the entry point 64 | startAnalysisFromEntry() 65 | 66 | # Add a callback. 67 | insertCall(before, INSERT_POINT.BEFORE) 68 | 69 | # Run the instrumentation - Never returns 70 | runProgram() 71 | 72 | 73 | -------------------------------------------------------------------------------- /Taint_analysis_and_pattern_matching_with_Pin/Example-1-Simple-taint-a-memory-area.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - Copyright (C) 2013-08 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Example 1 - http://shell-storm.org/blog/Taint-analysis-with-Pin/ 8 | // Simple taint memory area from read syscall. 9 | // 10 | 11 | #include "pin.H" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* bytes range tainted */ 18 | struct range 19 | { 20 | UINT64 start; 21 | UINT64 end; 22 | }; 23 | 24 | std::list bytesTainted; 25 | 26 | INT32 Usage() 27 | { 28 | cerr << "Ex 1" << endl; 29 | return -1; 30 | } 31 | 32 | VOID ReadMem(UINT64 insAddr, std::string insDis, UINT64 memOp) 33 | { 34 | list::iterator i; 35 | UINT64 addr = memOp; 36 | 37 | for(i = bytesTainted.begin(); i != bytesTainted.end(); ++i){ 38 | if (addr >= i->start && addr < i->end){ 39 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis<< std::endl; 40 | } 41 | } 42 | } 43 | 44 | VOID WriteMem(UINT64 insAddr, std::string insDis, UINT64 memOp) 45 | { 46 | list::iterator i; 47 | UINT64 addr = memOp; 48 | 49 | for(i = bytesTainted.begin(); i != bytesTainted.end(); ++i){ 50 | if (addr >= i->start && addr < i->end){ 51 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 52 | } 53 | } 54 | } 55 | 56 | VOID Instruction(INS ins, VOID *v) 57 | { 58 | if (INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 59 | INS_InsertCall( 60 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 61 | IARG_ADDRINT, INS_Address(ins), 62 | IARG_PTR, new string(INS_Disassemble(ins)), 63 | IARG_MEMORYOP_EA, 0, 64 | IARG_END); 65 | } 66 | else if (INS_MemoryOperandIsWritten(ins, 0)){ 67 | INS_InsertCall( 68 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 69 | IARG_ADDRINT, INS_Address(ins), 70 | IARG_PTR, new string(INS_Disassemble(ins)), 71 | IARG_MEMORYOP_EA, 0, 72 | IARG_END); 73 | } 74 | } 75 | 76 | static unsigned int lock; 77 | 78 | #define TRICKS(){if (lock++ == 0)return;} 79 | 80 | /* Taint from Syscalls */ 81 | VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 82 | { 83 | struct range taint; 84 | 85 | /* Taint from read */ 86 | if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ 87 | 88 | TRICKS(); 89 | 90 | taint.start = static_cast((PIN_GetSyscallArgument(ctx, std, 1))); 91 | taint.end = taint.start + static_cast((PIN_GetSyscallArgument(ctx, std, 2))); 92 | bytesTainted.push_back(taint); 93 | std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << taint.start << " to 0x" << taint.end << " (via read)"<< std::endl; 94 | } 95 | } 96 | 97 | int main(int argc, char *argv[]) 98 | { 99 | if(PIN_Init(argc, argv)){ 100 | return Usage(); 101 | } 102 | 103 | PIN_SetSyntaxIntel(); 104 | PIN_AddSyscallEntryFunction(Syscall_entry, 0); 105 | INS_AddInstrumentFunction(Instruction, 0); 106 | PIN_StartProgram(); 107 | 108 | return 0; 109 | } 110 | 111 | -------------------------------------------------------------------------------- /elf-corruption-little-anti-debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2013 - Jonathan Salwan - http://twitter.com/JonathanSalwan 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | ** 17 | ** 18 | ** See http://shell-storm.org/blog/Linux-process-execution-and-the-useless-ELF-header-fields/ 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | Elf32_Ehdr *pElf_Header; 31 | Elf32_Phdr *pElf32_Phdr; 32 | Elf32_Shdr *pElf32_Shdr; 33 | char *pMapElf; 34 | struct stat filestat; 35 | 36 | static unsigned char *set_header(char *file) 37 | { 38 | int fd; 39 | unsigned char *data; 40 | 41 | fd = open(file, O_RDONLY, 0644); 42 | stat(file, &filestat); 43 | printf("[+] Binary size : %d octets\n", (int)filestat.st_size); 44 | data = malloc(filestat.st_size * sizeof(char)); 45 | read(fd, data, filestat.st_size); 46 | pMapElf = mmap(0, filestat.st_size, PROT_READ, MAP_SHARED, fd, 0); 47 | pElf_Header = (Elf32_Ehdr *)data; 48 | pElf32_Shdr = (Elf32_Shdr *)((char *)data + pElf_Header->e_shoff); 49 | pElf32_Phdr = (Elf32_Phdr *)((char *)data + pElf_Header->e_phoff); 50 | close(fd); 51 | 52 | return (data); 53 | } 54 | 55 | int main(int argc, char **argv) 56 | { 57 | unsigned char *data; 58 | unsigned nb_section; 59 | Elf32_Shdr *current; 60 | int i, fd; 61 | 62 | if (argc < 2){ 63 | printf("Syntax: ./%s \n", argv[0]); 64 | return -1; 65 | } 66 | 67 | data = set_header(argv[1]); 68 | 69 | printf("--- Step 1 ---\n"); 70 | printf("[+] Clean sections...\n"); 71 | nb_section = pElf_Header->e_shnum; 72 | for (i = 0 ; i < nb_section ; i++){ 73 | pElf32_Shdr->sh_name = 0; 74 | pElf32_Shdr->sh_type = 0; 75 | pElf32_Shdr->sh_flags = 0; 76 | pElf32_Shdr->sh_addr = 0; 77 | pElf32_Shdr->sh_offset = 0; 78 | pElf32_Shdr->sh_size = 0; 79 | pElf32_Shdr->sh_link = 0; 80 | pElf32_Shdr->sh_info = 0; 81 | pElf32_Shdr->sh_addralign = 0; 82 | pElf32_Shdr->sh_entsize = 0; 83 | pElf32_Shdr++; 84 | } 85 | printf("[+] Clean section [DONE]\n"); 86 | 87 | printf("--- Step 2 ---\n"); 88 | printf("[+] Clean elf header...\n"); 89 | pElf_Header->e_shnum = 0; 90 | pElf_Header->e_shstrndx = 0; 91 | pElf_Header->e_shentsize = 0; 92 | pElf_Header->e_version = 0; 93 | pElf_Header->e_ehsize = 0; 94 | pElf_Header->e_shoff = 123; 95 | printf("[+] Clean elf header [DONE]\n"); 96 | 97 | printf("--- Step 3 ---\n"); 98 | printf("[+] Writting binary...\n"); 99 | fd = open(argv[1], O_WRONLY, 0644); 100 | write(fd, data, filestat.st_size); 101 | close(fd); 102 | printf("[+] Writting binary [DONE]\n"); 103 | 104 | free(data); 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /binary_analysis_with_ins_counts/inscount0.cpp: -------------------------------------------------------------------------------- 1 | /*BEGIN_LEGAL 2 | Intel Open Source License 3 | 4 | Copyright (c) 2002-2012 Intel Corporation. All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. Redistributions 12 | in binary form must reproduce the above copyright notice, this list of 13 | conditions and the following disclaimer in the documentation and/or 14 | other materials provided with the distribution. Neither the name of 15 | the Intel Corporation nor the names of its contributors may be used to 16 | endorse or promote products derived from this software without 17 | specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR 23 | ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | END_LEGAL */ 31 | #include 32 | #include 33 | #include "pin.H" 34 | 35 | ofstream OutFile; 36 | 37 | // The running count of instructions is kept here 38 | // make it static to help the compiler optimize docount 39 | static UINT64 icount = 0; 40 | 41 | // This function is called before every instruction is executed 42 | VOID docount() { icount++; } 43 | 44 | // Pin calls this function every time a new instruction is encountered 45 | VOID Instruction(INS ins, VOID *v) 46 | { 47 | // Insert a call to docount before every instruction, no arguments are passed 48 | INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END); 49 | } 50 | 51 | KNOB KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", 52 | "o", "inscount.out", "specify output file name"); 53 | 54 | // This function is called when the application exits 55 | VOID Fini(INT32 code, VOID *v) 56 | { 57 | // Write to a file since cout and cerr maybe closed by the application 58 | OutFile.setf(ios::showbase); 59 | OutFile << "Count " << icount << endl; 60 | OutFile.close(); 61 | } 62 | 63 | /* ===================================================================== */ 64 | /* Print Help Message */ 65 | /* ===================================================================== */ 66 | 67 | INT32 Usage() 68 | { 69 | cerr << "This tool counts the number of dynamic instructions executed" << endl; 70 | cerr << endl << KNOB_BASE::StringKnobSummary() << endl; 71 | return -1; 72 | } 73 | 74 | /* ===================================================================== */ 75 | /* Main */ 76 | /* ===================================================================== */ 77 | /* argc, argv are the entire command line: pin -t -- ... */ 78 | /* ===================================================================== */ 79 | 80 | int main(int argc, char * argv[]) 81 | { 82 | // Initialize pin 83 | if (PIN_Init(argc, argv)) return Usage(); 84 | 85 | OutFile.open(KnobOutputFile.Value().c_str()); 86 | 87 | // Register Instruction to be called to instrument instructions 88 | INS_AddInstrumentFunction(Instruction, 0); 89 | 90 | // Register Fini to be called when the application exits 91 | PIN_AddFiniFunction(Fini, 0); 92 | 93 | // Start the program, never returns 94 | PIN_StartProgram(); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /triton/format_string_bug_analysis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Triton tool for format string bug analysis. 5 | ## Jonathan Salwan - 2015-04-29 6 | ## 7 | ## Description: 8 | ## ------------ 9 | ## 10 | ## This tool taints all arguments (*argv[]) and checks when a printf occurs if 11 | ## there is some tainted bytes in its first argument (RDI). If RDI points on a 12 | ## memory area which contains tainted bytes, that means there is a potential 13 | ## vulnerability. 14 | ## 15 | ## 16 | ## Output: 17 | ## ------- 18 | ## 19 | ## $ ./triton ./src/tools/format_string_bug_analysis.py ./src/samples/vulns/formatString abcd titutatatoto 20 | ## [+] 012 bytes tainted from the argv[2] (0x7fff367da0f9) pointer 21 | ## [+] 004 bytes tainted from the argv[1] (0x7fff367da0f4) pointer 22 | ## [+] 028 bytes tainted from the argv[0] (0x7fff367da0d7) pointer 23 | ## [+] Analyzing the printf prologue argument. 24 | ## [+] Possible format string bug found. The first argument contains some tainted bytes. 25 | ## [trace] 0x4005e6: mov byte ptr [rax], 0x0 26 | ## [trace] 0x4005e9: mov rax, qword ptr [rbp-0x8] 27 | ## [trace] 0x4005ed: mov rdi, rax 28 | ## [trace] 0x4005f0: mov eax, 0x0 29 | ## [trace] 0x4005f5: call 0x400460 30 | ## [trace] 0x400460: jmp qword ptr [rip+0x200bb2] 31 | ## [trace] 0x400466: push 0x0 32 | ## [trace] 0x40046b: jmp 0x400450 33 | ## [trace] 0x400450: push qword ptr [rip+0x200bb2] 34 | ## [trace] 0x400456: jmp qword ptr [rip+0x200bb4] 35 | ## abcd 36 | ## $ 37 | 38 | import os 39 | 40 | from triton import * 41 | from pintool import * 42 | 43 | 44 | COUNT = 0 45 | TRACE = list() 46 | TRACE_SIZE = 10 47 | 48 | 49 | # When a printf occurs, we check if the first argument (RDI) 50 | # contains some tainted byte. If it's true -> possible vulnerability. 51 | def printfAnalysis(threadId): 52 | print '[+] Analyzing the printf prologue argument.' 53 | arg = getCurrentRegisterValue(REG.RDI) 54 | index = 0 55 | while getCurrentMemoryValue(arg + index) != 0x00: 56 | if isMemoryTainted(arg + index) == True: 57 | print '[+] Possible format string bug found. The first argument contains some tainted bytes.' 58 | global TRACE 59 | for t in TRACE: 60 | print '\t [trace] %#x: %s' %(t[0], t[1]) 61 | return 62 | index += 1 63 | return 64 | 65 | 66 | # When the main function is called, we taint the *argv[] arguments. 67 | def mainAnalysis(threadId): 68 | 69 | rdi = getCurrentRegisterValue(REG.RDI) # argc 70 | rsi = getCurrentRegisterValue(REG.RSI) # argv 71 | 72 | while rdi != 0: 73 | argv = getCurrentMemoryValue(rsi + ((rdi-1) * CPUSIZE.QWORD), CPUSIZE.QWORD) 74 | offset = 0 75 | while getCurrentMemoryValue(argv + offset) != 0x00: 76 | taintMemory(argv + offset) 77 | offset += 1 78 | print '[+] %03d bytes tainted from the argv[%d] (%#x) pointer' %(offset, rdi-1, argv) 79 | rdi -= 1 80 | 81 | return 82 | 83 | 84 | # Only save the last TRACE_SIZE instructions for the trace dump 85 | # when a vulnerability is found. 86 | def trace(instruction): 87 | global COUNT 88 | global TRACE 89 | 90 | # Save 91 | if len(TRACE) < TRACE_SIZE: 92 | TRACE.append(tuple((instruction.getAddress(), instruction.getDisassembly()))) 93 | else: 94 | TRACE[COUNT % TRACE_SIZE] = tuple((instruction.getAddress(), instruction.getDisassembly())) 95 | 96 | COUNT += 1 97 | return 98 | 99 | 100 | if __name__ == '__main__': 101 | 102 | # Set architecture 103 | setArchitecture(ARCH.X86_64) 104 | 105 | # Start the symbolic analysis from the entry point 106 | startAnalysisFromEntry() 107 | 108 | # Only trace the targeted binary 109 | setupImageWhitelist(["formatString"]) 110 | 111 | # Add a callback. 112 | insertCall(printfAnalysis, INSERT_POINT.ROUTINE_ENTRY, 'printf') 113 | insertCall(mainAnalysis, INSERT_POINT.ROUTINE_ENTRY, 'main') 114 | insertCall(trace, INSERT_POINT.AFTER) 115 | 116 | # Run the instrumentation - Never returns 117 | runProgram() 118 | 119 | 120 | -------------------------------------------------------------------------------- /syscalltable_hook_detection/syscalltable_hook_detection.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2013 - Jonathan Salwan - http://twitter.com/JonathanSalwan 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | ** 17 | ** For more information about this module, 18 | ** see : http://shell-storm.org/blog/Simple-Hook-detection-Linux-module/ 19 | ** 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #define PATH_PYTHON "/usr/bin/python2.7" 32 | #define PATH_SCRIPT "/opt/scripts/hook_detected.py" 33 | 34 | #define TIME_SLEEP 30000 /* in msec */ 35 | 36 | static struct timer_list timer_s; 37 | static struct workqueue_struct *wq; 38 | static unsigned int syscall_table_size; 39 | static unsigned long *addr_syscall_table; 40 | static unsigned long *dump_syscall_table; 41 | 42 | static int exec_python_script(unsigned int sys_num) 43 | { 44 | char s_num[32]; 45 | char *argv[] = {PATH_PYTHON, PATH_SCRIPT, s_num, NULL}; 46 | static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL}; 47 | struct subprocess_info *sub_info; 48 | 49 | sprintf(s_num, "%d", sys_num); 50 | sub_info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC); 51 | if (sub_info == NULL) 52 | return -ENOMEM; 53 | call_usermodehelper_exec(sub_info, UMH_WAIT_PROC); 54 | return 0; 55 | } 56 | 57 | static unsigned long *get_syscalls_table(void) 58 | { 59 | unsigned long *start; 60 | 61 | /* hack :/ */ 62 | for (start = (unsigned long *)0xc0000000; start < (unsigned long *)0xffffffff; start++) 63 | if (start[__NR_close] == (unsigned long)sys_close){ 64 | return start; 65 | } 66 | return NULL; 67 | } 68 | 69 | static unsigned int get_size_syscalls_table(void) 70 | { 71 | unsigned int size = 0; 72 | 73 | while (addr_syscall_table[size++]); 74 | return size * sizeof(unsigned long *); 75 | } 76 | 77 | static void check_diff_handler(struct work_struct *w) 78 | { 79 | unsigned int sys_num = 0; 80 | 81 | while (addr_syscall_table[sys_num]){ 82 | if (addr_syscall_table[sys_num] != dump_syscall_table[sys_num]){ 83 | printk(KERN_INFO "hook_detection: Hook detected ! (syscall %d)\n", sys_num); 84 | write_cr0(read_cr0() & (~0x10000)); 85 | addr_syscall_table[sys_num] = dump_syscall_table[sys_num]; 86 | write_cr0(read_cr0() | 0x10000); 87 | exec_python_script(sys_num); 88 | printk(KERN_INFO "hook_detection: syscall %d is restored\n", sys_num); 89 | } 90 | sys_num++; 91 | } 92 | } 93 | static DECLARE_DELAYED_WORK(check_diff, check_diff_handler); 94 | 95 | static void timer_handler(unsigned long data) 96 | { 97 | unsigned long onesec; 98 | 99 | onesec = msecs_to_jiffies(1000); 100 | queue_delayed_work(wq, &check_diff, onesec); 101 | if (mod_timer(&timer_s, jiffies + msecs_to_jiffies(TIME_SLEEP))) 102 | printk(KERN_INFO "hook_detection: Failed to set timer\n"); 103 | } 104 | 105 | static int __init hook_detection_init(void) 106 | { 107 | addr_syscall_table = get_syscalls_table(); 108 | if (!addr_syscall_table){ 109 | printk(KERN_INFO "hook_detection: Failed - Address of syscalls table not found\n"); 110 | return -ECANCELED; 111 | } 112 | 113 | syscall_table_size = get_size_syscalls_table(); 114 | dump_syscall_table = kmalloc(syscall_table_size, GFP_KERNEL); 115 | if (!dump_syscall_table){ 116 | printk(KERN_INFO "hook_detection: Failed - Not enough memory\n"); 117 | return -ENOMEM; 118 | } 119 | memcpy(dump_syscall_table, addr_syscall_table, syscall_table_size); 120 | 121 | wq = create_singlethread_workqueue("hook_detection_wq"); 122 | 123 | setup_timer(&timer_s, timer_handler, 0); 124 | if (mod_timer(&timer_s, jiffies + msecs_to_jiffies(TIME_SLEEP))){ 125 | printk(KERN_INFO "hook_detection: Failed to set timer\n"); 126 | return -ECANCELED; 127 | } 128 | 129 | printk(KERN_INFO "hook_detection: Init OK\n"); 130 | return 0; 131 | } 132 | 133 | static void __exit hook_detection_exit(void) 134 | { 135 | if (wq) 136 | destroy_workqueue(wq); 137 | kfree(dump_syscall_table); 138 | del_timer(&timer_s); 139 | printk(KERN_INFO "hook_detection: Exit\n"); 140 | } 141 | 142 | module_init(hook_detection_init); 143 | module_exit(hook_detection_exit); 144 | 145 | MODULE_AUTHOR("Jonathan Salwan"); 146 | MODULE_DESCRIPTION("Hook Detection"); 147 | MODULE_LICENSE("GPL"); 148 | -------------------------------------------------------------------------------- /triton/use_after_free_bug_and_memory_leak_analysis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Triton tool for use-after-free bug analysis and memory leak. 5 | ## Jonathan Salwan - 2015-04-30 6 | ## 7 | ## Description: 8 | ## ------------ 9 | ## 10 | ## This tool maintains a free table (TF) and an allocation table (TA) which 11 | ## represent the states of pointers allocated/freed during the execution. 12 | ## When a LOAD or STORE instruction occurs, the tool checks if the memory 13 | ## access is referenced into TA or TF. 14 | ## 15 | ## If the memory access is in TF -> use-after-free. 16 | ## 17 | ## Output: 18 | ## ------- 19 | ## 20 | ## $ ./triton ./src/tools/use_after_free_bug_analysis.py ./src/samples/vulns/testSuite 21 | ## [+] TA <- (0x1bec010, 0x20) 22 | ## [+] TA <- (0x1bec040, 0x20) 23 | ## [+] TA -> (0x1bec010, 0x20) 24 | ## [+] TF <- (0x1bec010, 0x20) 25 | ## [!] Use-after-free (0x1bec020) at 0x4006cb: mov byte ptr [rax], 0x43 26 | ## [+] TF -> (0x1bec010, 0x20) 27 | ## [+] TA <- (0x1bec010, 0x20) 28 | ## [+] TA -> (0x1bec040, 0x20) 29 | ## [+] TF <- (0x1bec040, 0x20) 30 | ## 31 | ## Free table: 32 | ## (0x1bec040, 0x20) 33 | ## 34 | ## Allocation table: 35 | ## (0x1bec010, 0x20) 36 | ## 37 | ## [!] There is 32 bytes of leaked memory 38 | ## 39 | 40 | from triton import * 41 | from pintool import * 42 | 43 | TA = list() 44 | TF = list() 45 | TMP = None 46 | 47 | 48 | 49 | def mallocEntry(threadId): 50 | global TMP 51 | rdi = getCurrentRegisterValue(REG.RDI) 52 | TMP = rdi 53 | return 54 | 55 | 56 | 57 | def mallocExit(threadId): 58 | 59 | global TA 60 | global TF 61 | global TMP 62 | 63 | rax = getCurrentRegisterValue(REG.RAX) 64 | if rax != 0: 65 | for (delta, size) in TF: 66 | 67 | # Same area 68 | if delta == rax and TMP == size: 69 | print '[+] TF -> (%#x, %#x)' %(delta, size) 70 | TF.remove(tuple((delta, size))) 71 | print '[+] TA <- (%#x, %#x)' %(rax, TMP) 72 | TA.append(tuple((rax, TMP))) 73 | return 74 | 75 | # Area splitted 76 | if delta == rax and TMP != size: 77 | print '[+] TF -> (%#x, %#x)' %(delta, size) 78 | TF.remove(tuple((delta, size))) 79 | if TMP < size: 80 | print '[+] TF <- (%#x, %#x)' %(delta + TMP, size - TMP) 81 | TF.append(tuple((delta + TMP, size - TMP))) 82 | print '[+] TA <- (%#x, %#x)' %(rax, TMP) 83 | TA.append(tuple((rax, TMP))) 84 | return 85 | 86 | print '[+] TA <- (%#x, %#x)' %(rax, TMP) 87 | TA.append(tuple((rax, TMP))) 88 | 89 | return 90 | 91 | 92 | 93 | def freeEntry(threadId): 94 | 95 | global TA 96 | global TF 97 | 98 | rdi = getCurrentRegisterValue(REG.RDI) 99 | for (delta, size) in TA: 100 | if delta == rdi: 101 | print '[+] TA -> (%#x, %#x)' %(delta, size) 102 | TA.remove(tuple((delta, size))) 103 | print '[+] TF <- (%#x, %#x)' %(delta, size) 104 | TF.append(tuple((delta, size))) 105 | return 106 | 107 | for (delta, size) in TF: 108 | if delta == rdi: 109 | print '[!] Double free bug found' 110 | return 111 | 112 | print '[!] Invalid free bug found with the pointer %#x' %(rdi) 113 | return 114 | 115 | 116 | 117 | def trace(instruction): 118 | global TF 119 | for operand in instruction.getOperands(): 120 | if operand.getType() == OPERAND.MEM: 121 | memoryAccess = operand.getAddress() 122 | memoryAccessSize = operand.getSize() 123 | for (delta, size) in TF: 124 | if memoryAccess > delta and memoryAccess < delta+size: 125 | print '[!] Use-after-free (%#x) at %#x: %s' %(memoryAccess, instruction.getAddress(), instruction.getDisassembly()) 126 | return 127 | return 128 | 129 | 130 | 131 | def fini(): 132 | global TA 133 | global TF 134 | 135 | print '\nFree table:' 136 | for (delta, size) in TF: 137 | print '\t(%#x, %#x)' %(delta, size) 138 | 139 | if len(TF) == 0: 140 | print '\tEmpty' 141 | 142 | memLeak = 0 143 | print '\nAllocation table:' 144 | for (delta, size) in TA: 145 | print '\t(%#x, %#x)' %(delta, size) 146 | memLeak += size 147 | 148 | if len(TA) == 0: 149 | print '\tEmpty' 150 | 151 | if memLeak > 0: 152 | print '\n[!] There is %d bytes of leaked memory' %(memLeak) 153 | 154 | return 155 | 156 | 157 | if __name__ == '__main__': 158 | 159 | # Set architecture 160 | setArchitecture(ARCH.X86_64) 161 | 162 | # Start the symbolic analysis from the entry point 163 | startAnalysisFromEntry() 164 | 165 | # Add a callback. 166 | insertCall(mallocEntry, INSERT_POINT.ROUTINE_ENTRY, 'malloc') 167 | insertCall(mallocExit, INSERT_POINT.ROUTINE_EXIT, 'malloc') 168 | insertCall(freeEntry, INSERT_POINT.ROUTINE_ENTRY, 'free') 169 | insertCall(trace, INSERT_POINT.AFTER) 170 | insertCall(fini, INSERT_POINT.FINI) 171 | 172 | # Run the instrumentation - Never returns 173 | runProgram() 174 | 175 | 176 | -------------------------------------------------------------------------------- /trace_linux_kernel_function.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2013 - Jonathan Salwan - http://twitter.com/JonathanSalwan 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | ** 17 | ** 18 | ** Little script to trace a specific kernel function and display 19 | ** arguments / call stack. Send your function name in the procfs 20 | ** node to start the tracing. Send 'none' in procfs node to stop 21 | ** the tracing. Below, a little example. 22 | ** 23 | ** # insmod ./trace.ko 24 | ** # cat /proc/trace_func 25 | ** Function traced : none 26 | ** # printf '__kmalloc' > /proc/trace_func 27 | ** # cat /proc/trace_func 28 | ** Function traced : __kmalloc 29 | ** # dmesg 30 | ** ... 31 | ** [ 1880.977375] ]=------------------------ 32 | ** [ 1880.977378] Function : __kmalloc 33 | ** [ 1880.977378] 34 | ** [ 1880.977380] args 0: 000000e0 args 1: 000000d0 args 2: cb0463c0 35 | ** [ 1880.977382] args 3: 00000003 args 4: 00001812 args 5: 00000000 36 | ** [ 1880.977382] 37 | ** [ 1880.977386] Pid: 6974, comm: dmesg Tainted: G O 3.5.7-gentoo #3 38 | ** [ 1880.977387] Call Trace: 39 | ** [ 1880.977391] [] trace+0x74/0xa0 [trace] 40 | ** [ 1880.977396] [] load_elf_binary+0x83a/0x11c0 41 | ** [ 1880.977400] [] ? _copy_from_user+0x3f/0x60 42 | ** [ 1880.977404] [] ? elf_map+0xc0/0xc0 43 | ** [ 1880.977408] [] search_binary_handler+0xc7/0x2c0 44 | ** [ 1880.977413] [] do_execve+0x2f0/0x3a0 45 | ** [ 1880.977418] [] sys_execve+0x32/0x70 46 | ** [ 1880.977423] [] ptregs_execve+0x12/0x18 47 | ** [ 1880.977427] [] ? sysenter_do_call+0x12/0x22 48 | ** [ 1880.977429] ]= EOF ------------------- 49 | ** # printf 'none' > /proc/trace_func 50 | ** 51 | ** 52 | ** See: http://shell-storm.org/blog/Trace-and-debug-the-Linux-Kernel-functons/ 53 | ** 54 | ** Tested on 3.5.7 custom kernel with gentoo. 55 | ** 56 | */ 57 | 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | 64 | static void trace(void *arg0, void *arg1, void *arg2, void *arg3, void *arg4, void *arg5); 65 | 66 | static struct jprobe jp = { 67 | .entry = JPROBE_ENTRY(trace), 68 | .kp = { 69 | .symbol_name = NULL, 70 | } 71 | }; 72 | 73 | static void trace(void *arg0, void *arg1, void *arg2, void *arg3, void *arg4, void *arg5) 74 | { 75 | printk("]=------------------------\n"); 76 | printk("Function : %s\n\n", jp.kp.symbol_name); 77 | printk("Arg0 : %08x Arg1 : %08x Arg2 : %08x\n", (unsigned int)arg0, (unsigned int)arg1, (unsigned int)arg2); 78 | printk("Arg3 : %08x Arg4 : %08x Arg5 : %08x\n\n", (unsigned int)arg3, (unsigned int)arg4, (unsigned int)arg5); 79 | dump_stack(); 80 | printk("]= EOF -------------------\n"); 81 | jprobe_return(); 82 | } 83 | 84 | static ssize_t handler_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) 85 | { 86 | int ret; 87 | 88 | if (jp.kp.symbol_name) 89 | kfree(jp.kp.symbol_name); 90 | 91 | jp.kp.symbol_name = kzalloc(count +1, GFP_KERNEL); 92 | if (!jp.kp.symbol_name) 93 | return -ENOMEM; 94 | 95 | memcpy((void*)jp.kp.symbol_name, (void *)buffer, count); 96 | if (!memcmp(jp.kp.symbol_name, "none", 4)){ 97 | kfree(jp.kp.symbol_name); 98 | jp.kp.symbol_name = NULL; 99 | unregister_jprobe(&jp); 100 | printk("trace: Tracing stoped\n"); 101 | return count; 102 | } 103 | else if ((ret = register_jprobe(&jp)) < 0) { 104 | printk("trace: register_jprobe failed, returned %d\n", ret); 105 | kfree(jp.kp.symbol_name); 106 | jp.kp.symbol_name = NULL; 107 | return -ENOSYS; 108 | } 109 | printk("trace: %s traced\n", jp.kp.symbol_name); 110 | return count; 111 | } 112 | 113 | static ssize_t handler_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) 114 | { 115 | int ret; 116 | 117 | if (!jp.kp.symbol_name){ 118 | sprintf(page, "Function traced : none\n"); 119 | ret = 23; 120 | } 121 | else { 122 | sprintf(page, "Function traceed : %s\n", jp.kp.symbol_name); 123 | ret = strlen(jp.kp.symbol_name) + 20; 124 | } 125 | return ret; 126 | } 127 | 128 | static int __init mod_init(void) 129 | { 130 | struct proc_dir_entry *proc_entry; 131 | 132 | proc_entry = create_proc_entry("trace", 0666, NULL); 133 | if (proc_entry){ 134 | proc_entry->write_proc = handler_proc_write; 135 | proc_entry->read_proc = handler_proc_read; 136 | } 137 | 138 | return 0; 139 | } 140 | 141 | static void __exit mod_exit(void) 142 | { 143 | unregister_jprobe(&jp); 144 | remove_proc_entry("trace", NULL); 145 | } 146 | 147 | module_init(mod_init); 148 | module_exit(mod_exit); 149 | 150 | MODULE_LICENSE("GPL"); 151 | 152 | 153 | -------------------------------------------------------------------------------- /Taint_analysis_and_pattern_matching_with_Pin/Example-6-Pointer-without-check-detection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - Copyright (C) 2013-08 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Example 6 - http://shell-storm.org/blog/Taint-analysis-with-Pin/ 8 | // Detect pointer utilization without check 9 | // 10 | 11 | #include "pin.H" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define LOCKED 1 18 | #define UNLOCKED !LOCKED 19 | 20 | #define ALLOCATE 1 21 | #define FREE !ALLOCATE 22 | 23 | #define CHECKED 1 24 | 25 | static size_t lastSize; 26 | 27 | struct mallocArea 28 | { 29 | UINT64 base; 30 | UINT64 size; 31 | BOOL status; 32 | BOOL check; 33 | }; 34 | 35 | UINT32 lockTaint = LOCKED; 36 | 37 | std::list addressTainted; 38 | std::list regsTainted; 39 | std::list mallocAreaList; 40 | 41 | INT32 Usage() 42 | { 43 | std::cerr << "Ex 6" << std::endl; 44 | return -1; 45 | } 46 | 47 | VOID ReadMem(UINT64 insAddr, std::string insDis, UINT64 memOp) 48 | { 49 | list::iterator i; 50 | UINT64 addr = memOp; 51 | 52 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 53 | if (i->base == addr && i->check != CHECKED) 54 | std::cout << std::hex << "[READ in " << addr << " without check]\t\t" << insAddr << ": " << insDis << std::endl; 55 | } 56 | } 57 | 58 | VOID WriteMem(UINT64 insAddr, std::string insDis, UINT64 memOp) 59 | { 60 | list::iterator i; 61 | UINT64 addr = memOp; 62 | 63 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 64 | if (i->base == addr && i->check != CHECKED) 65 | std::cout << std::hex << "[WRITE in " << addr << " without check]\t\t" << insAddr << ": " << insDis << std::endl; 66 | } 67 | } 68 | 69 | VOID cmpInst(UINT64 insAddr, std::string insDis, UINT64 memOp) 70 | { 71 | list::iterator i; 72 | UINT64 addr = memOp; 73 | 74 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 75 | if (*(UINT64 *)addr == i->base){ 76 | std::cout << std::hex << "[PTR " << *(UINT64 *)addr << " checked]\t\t\t" << insAddr << ": " << insDis << std::endl; 77 | i->check = CHECKED; 78 | } 79 | } 80 | } 81 | 82 | VOID testInst(UINT64 insAddr, std::string insDis, ADDRINT val_r0, ADDRINT val_r1) 83 | { 84 | list::iterator i; 85 | 86 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 87 | if (val_r0 == val_r1 && val_r0 == i->base){ 88 | std::cout << std::hex << "[PTR " << val_r0 << " checked]\t\t\t" << insAddr << ": " << insDis << std::endl; 89 | i->check = CHECKED; 90 | } 91 | } 92 | } 93 | 94 | VOID Instruction(INS ins, VOID *v) 95 | { 96 | if (INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 97 | INS_InsertCall( 98 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 99 | IARG_ADDRINT, INS_Address(ins), 100 | IARG_PTR, new string(INS_Disassemble(ins)), 101 | IARG_MEMORYOP_EA, 0, 102 | IARG_END); 103 | } 104 | else if (INS_MemoryOperandIsWritten(ins, 0)){ 105 | INS_InsertCall( 106 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 107 | IARG_ADDRINT, INS_Address(ins), 108 | IARG_PTR, new string(INS_Disassemble(ins)), 109 | IARG_MEMORYOP_EA, 0, 110 | IARG_END); 111 | } 112 | else if (INS_Opcode(ins) == XED_ICLASS_CMP && INS_OperandIsMemory(ins, 0)){ 113 | INS_InsertCall( 114 | ins, IPOINT_BEFORE, (AFUNPTR)cmpInst, 115 | IARG_ADDRINT, INS_Address(ins), 116 | IARG_PTR, new string(INS_Disassemble(ins)), 117 | IARG_MEMORYOP_EA, 0, 118 | IARG_END); 119 | } 120 | else if (INS_Opcode(ins) == XED_ICLASS_TEST && INS_OperandCount(ins) >= 2 && 121 | REG_valid(INS_OperandReg(ins, 0)) && REG_valid(INS_OperandReg(ins, 1))){ 122 | INS_InsertCall( 123 | ins, IPOINT_BEFORE, (AFUNPTR)testInst, 124 | IARG_ADDRINT, INS_Address(ins), 125 | IARG_PTR, new string(INS_Disassemble(ins)), 126 | IARG_REG_VALUE, INS_OperandReg(ins, 0), 127 | IARG_REG_VALUE, INS_OperandReg(ins, 1), 128 | IARG_END); 129 | } 130 | } 131 | 132 | VOID callbackBeforeMalloc(ADDRINT size) 133 | { 134 | lastSize = size; 135 | } 136 | 137 | VOID callbackBeforeFree(ADDRINT addr) 138 | { 139 | list::iterator i; 140 | 141 | std::cout << "[INFO]\t\t\t\t\tfree(" << std::hex << addr << ")" << std::endl; 142 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 143 | if (addr == i->base){ 144 | i->status = FREE; 145 | break; 146 | } 147 | } 148 | } 149 | 150 | VOID callbackAfterMalloc(ADDRINT ret) 151 | { 152 | list::iterator i; 153 | struct mallocArea elem; 154 | 155 | std::cout << "[INFO]\t\t\t\t\tmalloc(" << lastSize << ") = " << std::hex << ret << std::endl; 156 | if (ret){ 157 | 158 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 159 | if (ret == i->base){ 160 | i->status = ALLOCATE; 161 | i->size = lastSize; 162 | i->check = !CHECKED; 163 | return; 164 | } 165 | } 166 | elem.base = ret; 167 | elem.size = lastSize; 168 | elem.status = ALLOCATE; 169 | elem.check = !CHECKED; 170 | mallocAreaList.push_front(elem); 171 | } 172 | } 173 | 174 | VOID Image(IMG img, VOID *v) 175 | { 176 | RTN mallocRtn = RTN_FindByName(img, "malloc"); 177 | RTN freeRtn = RTN_FindByName(img, "free"); 178 | 179 | if (RTN_Valid(mallocRtn)){ 180 | RTN_Open(mallocRtn); 181 | 182 | RTN_InsertCall( 183 | mallocRtn, 184 | IPOINT_BEFORE, (AFUNPTR)callbackBeforeMalloc, 185 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, 186 | IARG_END); 187 | 188 | RTN_InsertCall( 189 | mallocRtn, 190 | IPOINT_AFTER, (AFUNPTR)callbackAfterMalloc, 191 | IARG_FUNCRET_EXITPOINT_VALUE, 192 | IARG_END); 193 | 194 | RTN_Close(mallocRtn); 195 | } 196 | 197 | if (RTN_Valid(freeRtn)){ 198 | RTN_Open(freeRtn); 199 | RTN_InsertCall( 200 | freeRtn, 201 | IPOINT_BEFORE, (AFUNPTR)callbackBeforeFree, 202 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, 203 | IARG_END); 204 | RTN_Close(freeRtn); 205 | } 206 | } 207 | 208 | int main(int argc, char *argv[]) 209 | { 210 | PIN_InitSymbols(); 211 | if(PIN_Init(argc, argv)){ 212 | return Usage(); 213 | } 214 | 215 | PIN_SetSyntaxIntel(); 216 | IMG_AddInstrumentFunction(Image, 0); 217 | INS_AddInstrumentFunction(Instruction, 0); 218 | PIN_StartProgram(); 219 | 220 | return 0; 221 | } 222 | 223 | -------------------------------------------------------------------------------- /base_serv.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Copyright (C) 2013 - Jonathan Salwan - http://twitter.com/JonathanSalwan 3 | ** 4 | ** This program is free software: you can redistribute it and/or modify 5 | ** it under the terms of the GNU General Public License as published by 6 | ** the Free Software Foundation, either version 3 of the License, or 7 | ** (at your option) any later version. 8 | ** 9 | ** This program is distributed in the hope that it will be useful, 10 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ** GNU General Public License for more details. 13 | ** 14 | ** You should have received a copy of the GNU General Public License 15 | ** along with this program. If not, see . 16 | ** 17 | ** 18 | ** $ gcc -W -Wall -Wextra -ansi -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE \ 19 | ** -lpthread -std=c99 -o base_serv ./base_serv.c 20 | ** 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define SERV_PORT 1024 37 | #define MAX_CLIENT 256 38 | #define MAX_CLIENT_QUEUE 32 39 | 40 | #define TRUE 0 41 | #define FALSE !TRUE 42 | #define SUCCESS 0 43 | #define ERROR !SUCCESS 44 | 45 | #define __PRIVATE__ 46 | #define __API__ 47 | 48 | typedef struct client_s { 49 | unsigned char buff[256]; 50 | int32_t fd; 51 | struct sockaddr_in addr; 52 | struct client_s *next; 53 | struct client_s *prev; 54 | } client_t; 55 | 56 | typedef struct api_s { 57 | void(*addClient)(client_t*); 58 | void(*delClient)(client_t*); 59 | } api_t; 60 | 61 | typedef struct coreServ_s { 62 | /* Attributs */ 63 | int32_t fd; 64 | int32_t on; 65 | client_t *clients; 66 | client_t *fclient; 67 | api_t api; 68 | struct sockaddr_in addr; 69 | struct timeval timeout; 70 | pthread_t threadConHandler; 71 | pthread_t threadMoniClient; 72 | pthread_mutex_t mutex; 73 | fd_set readfs; 74 | /* Methodes */ 75 | void(*initSocket)(void); 76 | void(*startServ)(void); 77 | void*(*waitingClient)(void*); 78 | void*(*monitoringClient)(void*); 79 | } coreServ_t; 80 | 81 | static void __PRIVATE__ initSockServ(void); 82 | static void __PRIVATE__ startServ(void); 83 | static void __PRIVATE__ *servWaitingClient(void*); 84 | static void __PRIVATE__ *monitoringClient(void*); 85 | static void __API__ addClient(client_t *newCli); 86 | static void __API__ delClient(client_t *newCli); 87 | 88 | coreServ_t coreServ = { 89 | .fd = 0, 90 | .clients = NULL, 91 | .initSocket = __PRIVATE__ initSockServ, 92 | .startServ = __PRIVATE__ startServ, 93 | .waitingClient = __PRIVATE__ servWaitingClient, 94 | .monitoringClient = __PRIVATE__ monitoringClient, 95 | .api = { 96 | .delClient = __API__ delClient, 97 | .addClient = __API__ addClient, 98 | }, 99 | .timeout = { 100 | .tv_usec = 0, 101 | .tv_sec = 1, 102 | } 103 | }; 104 | 105 | static void __PRIVATE__ initSockServ(void){ 106 | if ((coreServ.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 107 | perror("initSockServ.socket"); 108 | exit(-1); 109 | } 110 | if (setsockopt(coreServ.fd, SOL_SOCKET, SO_REUSEADDR, (char*)&coreServ.on, sizeof(int)) < 0){ 111 | perror("initSockServ.setsockopt"); 112 | close(coreServ.fd); 113 | exit(-1); 114 | } 115 | memset(&coreServ.addr, 0x00, sizeof(struct sockaddr_in)); 116 | coreServ.addr.sin_family = AF_INET; 117 | coreServ.addr.sin_port = htons(SERV_PORT); 118 | coreServ.addr.sin_addr.s_addr = htonl(INADDR_ANY); 119 | } 120 | 121 | static void __API__ addClient(client_t *newCli){ 122 | pthread_mutex_lock(&coreServ.mutex); 123 | if (coreServ.clients != NULL){ 124 | newCli->next = coreServ.clients->next; 125 | newCli->prev = coreServ.clients; 126 | coreServ.clients->next = newCli; 127 | coreServ.fclient->prev = newCli; 128 | coreServ.clients = newCli; 129 | } 130 | else { 131 | newCli->next = newCli; 132 | newCli->prev = newCli; 133 | coreServ.clients = newCli; 134 | coreServ.fclient = newCli; 135 | } 136 | pthread_mutex_unlock(&coreServ.mutex); 137 | } 138 | 139 | static void __API__ delClient(client_t *cli){ 140 | if (cli->next == cli && cli->prev == cli){ 141 | coreServ.clients = NULL; 142 | coreServ.fclient = NULL; 143 | } 144 | else { 145 | cli->prev->next = cli->next; 146 | cli->next->prev = cli->prev; 147 | if (cli == coreServ.fclient){ 148 | coreServ.fclient = cli->next; 149 | } 150 | if (cli == coreServ.clients){ 151 | coreServ.clients = cli->next; 152 | } 153 | } 154 | free(cli); 155 | } 156 | 157 | static void __PRIVATE__ *servWaitingClient(void *args){ 158 | struct sockaddr_in cliAddr; 159 | int32_t fdCli; 160 | uint32_t sinSize; 161 | client_t *newClient; 162 | 163 | (void)args; 164 | sinSize = sizeof(struct sockaddr_in); 165 | if (bind(coreServ.fd, (struct sockaddr *)&coreServ.addr, sizeof(coreServ.addr)) < 0){ 166 | perror("ServWaitingClient.bind"); 167 | close(coreServ.fd); 168 | exit(-1); 169 | } 170 | if (listen(coreServ.fd, MAX_CLIENT_QUEUE) < 0){ 171 | perror("ServWaitingClient.listen"); 172 | close(coreServ.fd); 173 | exit(-1); 174 | } 175 | while (1){ 176 | if ((fdCli = accept(coreServ.fd, (struct sockaddr *)&cliAddr, &sinSize)) < 0){ 177 | perror("ServWaitingClient.accept"); 178 | close(coreServ.fd); 179 | exit(-1); 180 | } 181 | if ((newClient = malloc(sizeof(client_t))) == NULL){ 182 | perror("ServWaitingClient.malloc"); 183 | continue; 184 | } 185 | newClient->fd = fdCli; 186 | newClient->addr = cliAddr; 187 | coreServ.api.addClient(newClient); 188 | } 189 | /* never go here */ 190 | pthread_exit(0); 191 | } 192 | 193 | static void __PRIVATE__ fdSetAll(void){ 194 | client_t *ptr; 195 | int stop = 0; 196 | 197 | pthread_mutex_lock(&coreServ.mutex); 198 | ptr = coreServ.clients; 199 | FD_ZERO(&coreServ.readfs); 200 | while (ptr && ptr->fd != stop){ 201 | if (stop == 0) 202 | stop = ptr->fd; 203 | FD_SET(ptr->fd, &coreServ.readfs); 204 | ptr = ptr->next; 205 | } 206 | pthread_mutex_unlock(&coreServ.mutex); 207 | } 208 | 209 | static void __PRIVATE__ fdIssetAll(void){ 210 | client_t *ptr; 211 | int stop = 0; 212 | int ret = 0; 213 | 214 | pthread_mutex_lock(&coreServ.mutex); 215 | ptr = coreServ.clients; 216 | while (ptr && ptr->fd != stop){ 217 | if (stop == 0) 218 | stop = ptr->fd; 219 | if (FD_ISSET(ptr->fd, &coreServ.readfs)){ 220 | memset(ptr->buff, 0x00, sizeof(ptr->buff)); 221 | ret = read(ptr->fd, ptr->buff, sizeof(ptr->buff)-1); 222 | if (ret <= 0){ 223 | printf("Close (%d)\n", ptr->fd); 224 | if (ptr->fd == stop) 225 | stop = ptr->next->fd; 226 | coreServ.api.delClient(ptr); 227 | } 228 | else { 229 | /* Just change that call */ 230 | printf("ret=%d | Client (%d): %s", ret, ptr->fd, ptr->buff); 231 | } 232 | } 233 | ptr = ptr->next; 234 | } 235 | pthread_mutex_unlock(&coreServ.mutex); 236 | } 237 | 238 | static int __PRIVATE__ getMaxFd(void){ 239 | client_t *ptr; 240 | int max; 241 | 242 | pthread_mutex_lock(&coreServ.mutex); 243 | ptr = coreServ.clients; 244 | max = (ptr == 0) ? coreServ.fd : coreServ.clients->fd; 245 | while (ptr != coreServ.fclient){ 246 | if (ptr->fd > max) 247 | max = ptr->fd; 248 | ptr = ptr->next; 249 | } 250 | pthread_mutex_unlock(&coreServ.mutex); 251 | return max; 252 | } 253 | 254 | static void __PRIVATE__ *monitoringClient(void *args){ 255 | client_t *ptr = NULL; 256 | int ret = 0; 257 | 258 | (void)args; 259 | while(1){ 260 | if (ptr){ 261 | fdSetAll(); 262 | if ((ret = select(getMaxFd() + 1, &coreServ.readfs, NULL, NULL, &coreServ.timeout)) == -1){ 263 | perror("monitoringClient.select"); 264 | close(coreServ.fd); 265 | exit(-1); 266 | } 267 | else if (ret > 0){ 268 | fdIssetAll(); 269 | } 270 | ptr = ptr->next; 271 | } 272 | else { 273 | ptr = coreServ.clients; 274 | } 275 | usleep(500); 276 | } 277 | /* never go here */ 278 | pthread_exit(0); 279 | } 280 | 281 | static void __PRIVATE__ startServ(void){ 282 | void *ret; 283 | 284 | if (pthread_create(&coreServ.threadConHandler, NULL, coreServ.waitingClient, NULL) < 0){ 285 | perror("startServ.pthread_create (1)"); 286 | exit(1); 287 | } 288 | if (pthread_create(&coreServ.threadMoniClient, NULL, coreServ.monitoringClient, NULL) < 0){ 289 | perror("startServ.pthread_create (2)"); 290 | exit(1); 291 | } 292 | (void)pthread_join(coreServ.threadConHandler, &ret); 293 | (void)pthread_join(coreServ.threadMoniClient, &ret); 294 | } 295 | 296 | int main(int ac, const char *av[]){ 297 | (void)ac; 298 | (void)av; 299 | 300 | coreServ.initSocket(); 301 | coreServ.startServ(); 302 | 303 | return 0; 304 | } 305 | -------------------------------------------------------------------------------- /metaSample.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | ## -*- coding: utf-8 -*- 3 | ## 4 | ## Jonathan Salwan - 2014-01-27 5 | ## 6 | ## http://www.shell-storm.org/ 7 | ## http://twitter.com/JonathanSalwan 8 | ## 9 | ## This program is free software: you can redistribute it and/or modify 10 | ## it under the terms of the GNU General Public License as published by 11 | ## the Free Software Foundation, either version 3 of the License, or 12 | ## (at your option) any later version. 13 | ## 14 | ## Note: Just a simple way to generate valid samples. You can use script before compiling 15 | ## your sources (metaprog) or on raw files. 16 | ## 17 | ## ================================= 18 | ## 19 | ## Meta patterns supported: 20 | ## 21 | ## __GENINTDEC#:[:]__ == Generates the same file with all range values in decimal. 22 | ## __GENINTHEX#:[:]__ == Generates the same file with all range values in hexadecimal. 23 | ## __GENSTR#:[,,,...]__ == Generates the same file with all strings listed. 24 | ## 25 | ## ================================= 26 | ## 27 | ## Example 1: 28 | ## 29 | ## #include 30 | ## 31 | ## int main(int ac, const char *av[]) 32 | ## { 33 | ## int a, b, c; 34 | ## char *str1, *str2; 35 | ## 36 | ## a = __GENINTDEC#1:[-3:2]__; 37 | ## b = __GENINTDEC#2:[6:10]__; 38 | ## c = 7; 39 | ## 40 | ## str1 = "fixe"; 41 | ## str2 = __GENSTR#1:["AAAAAAAAAAAA","%x%x%x%x%x%x%x%x",NULL,"\x00\x01\x02\x03\x04"]__; 42 | ## 43 | ## foo(a, b, c, str1, str2); 44 | ## } 45 | ## 46 | ## ================================= 47 | ## 48 | ## Example 2: 49 | ## 50 | ## #include 51 | ## #include 52 | ## 53 | ## int main(int ac, const char *av[]) 54 | ## { 55 | ## int sockfd; 56 | ## 57 | ## sockfd = socket(__GENSTR#1:[AF_UNIX,AF_INET,AF_INET6,AF_IPX,AF_NETLINK,AF_X25,AF_AX25,AF_ATMPVC,AF_APPLETALK,AF_PACKET]__, 58 | ## __GENSTR#2:[SOCK_STREAM,SOCK_DGRAM,SOCK_SEQPACKET,SOCK_RAW,SOCK_RDM,SOCK_PACKET]__, 59 | ## __GENINTDEC#1:[0:10]__); 60 | ## /* ... */ 61 | ## } 62 | ## 63 | ## ================================= 64 | ## 65 | ## Example 3: 66 | ## 67 | ## 60 23 40 00 00 00 00 00 00 00 00 00 00 00 00 00 68 | ## 01 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 69 | ## 0c 00 00 00 00 00 00 00 b0 15 40 00 00 00 00 00 70 | ## 0d 00 00 00 00 00 00 00 6c 53 40 00 00 00 00 00 71 | ## 19 00 00 00 00 00 00 00 f8 7d 60 00 00 00 00 00 72 | ## 1b 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 73 | ## 1a 00 00 00 00 00 00 00 00 7e 60 00 __GENINTHEX#1:[128:129]__ 00 00 00 74 | ## 1c 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 75 | ## 04 00 00 00 00 00 00 00 b0 02 40 00 00 00 00 00 76 | ## f5 fe ff 6f 00 00 00 00 70 05 40 00 00 00 00 00 77 | ## 05 00 00 00 00 00 00 00 18 0c 40 00 00 00 00 00 78 | ## 06 00 00 00 00 00 00 00 d0 05 40 00 00 00 00 00 79 | ## 0a 00 00 __GENINTHEX#2:[44:51]__ 00 00 00 00 a5 02 00 00 00 00 00 00 80 | ## 0b 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 81 | ## 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 82 | ## 03 00 00 00 00 00 00 00 00 80 60 00 00 00 00 00 83 | ## 02 00 00 00 00 00 00 00 88 05 00 00 00 00 00 00 84 | ## 14 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 85 | ## 17 00 00 00 00 00 00 00 28 10 40 00 00 00 00 00 86 | ## 07 00 00 00 00 00 00 00 98 0f 40 00 __GENINTHEX#3:[20:25]__ 00 00 00 87 | ## 08 00 00 00 00 00 00 00 90 00 00 00 00 00 00 00 88 | ## 09 00 00 00 00 00 00 00 18 00 00 00 00 00 00 00 89 | ## fe ff ff 6f 00 00 00 00 48 0f 40 00 00 00 00 00 90 | ## ff ff ff 6f 00 00 00 00 01 00 00 00 00 00 00 00 91 | ## f0 ff ff 6f 00 00 00 00 be 0e 40 00 00 00 00 00 92 | ## 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 93 | ## 94 | ## ================================= 95 | ## 96 | ## Using example: 97 | ## 98 | ## $ ./metaSample.py --file src_examples/example_1.c --outputDir ./output -v 99 | ## [+] Opening file: src_examples/example_1.c 100 | ## [+] Finding metadata... 101 | ## [+] Metadata found: 102 | ## -> __GENINTDEC#1:[-3:2]__ 103 | ## -> __GENINTDEC#2:[6:10]__ 104 | ## -> __GENSTR#1:["AAAAAAAAAAAA","%x%x%x%x%x%x%x%x",NULL,"\x00\x01\x02\x03\x04"]__ 105 | ## [+] Generating samples in progress... 106 | ## [+] Number of samples generated: 120 107 | ## 108 | ## 109 | 110 | import getopt 111 | import hashlib 112 | import re 113 | import sys 114 | 115 | class metaSample: 116 | 117 | def __init__(self): 118 | self.__fileName = "" 119 | self.__outputDir = "/tmp" 120 | self.__verbose = False 121 | self.__numSampleGen = 0 122 | 123 | """ verbose attribute getter """ 124 | def getVerbose(self): 125 | return self.__verbose 126 | 127 | """ fileName attribute getter. """ 128 | def getFileName(self): 129 | return self.__fileName 130 | 131 | """ outputDir attribute getter. """ 132 | def getOutputDir(self): 133 | return self.__outputDir 134 | 135 | """ Print help function. """ 136 | def printHelp(self): 137 | print "Syntax: metaSample.py [options] (args)\n" 138 | print "Options:" 139 | print "\t-h, --help\t\tPrint help" 140 | print "\t-f, --file\t\tSpecifies an input file" 141 | print "\t-o, --outputDir\t\tSpecifies an output directory" 142 | sys.exit(1) 143 | 144 | """ getOpt function. Need sys.argv in parameter. """ 145 | def getOpt(self, argv): 146 | try: 147 | opts, args = getopt.getopt(argv, "hfo:v", ["help", "file=", "outputDir="]) 148 | except getopt.GetoptError: 149 | self.printHelp() 150 | 151 | for opt, arg in opts: 152 | if opt == "-v": 153 | self.__verbose = True 154 | elif opt in ("-h", "--help"): 155 | self.printHelp() 156 | elif opt in ("-f", "--file"): 157 | self.__fileName = arg 158 | elif opt in ("-o", "--outputDir"): 159 | self.__outputDir = arg 160 | 161 | """ This function generate the samples base on the input file. """ 162 | def generate(self): 163 | if not self.__fileName: 164 | print "[-] Error: input file not found. Please see --help." 165 | sys.exit(-1) 166 | self.__constructMeta() 167 | 168 | def __constructMeta(self): 169 | if self.getVerbose() == True: 170 | print "[+] Opening file: %s" %(self.getFileName()) 171 | 172 | try: 173 | f = open(self.getFileName(), "r") 174 | raw = f.read() 175 | f.close() 176 | except: 177 | print "[-] Error: Can't open or read the file: %s" %(self.getFileName()) 178 | sys.exit(-1) 179 | 180 | if self.getVerbose() == True: 181 | print "[+] Finding metadata..." 182 | metadata = re.findall(r'__GEN.*?__', raw) 183 | 184 | if self.getVerbose() == True: 185 | print "[+] Metadata found:" 186 | for elem in metadata: 187 | print " -> %s" %(elem) 188 | self.__genFile(raw, metadata) 189 | 190 | def saveGeneratedFile(self, raw): 191 | m = hashlib.md5() 192 | m.update(raw) 193 | path = self.getFileName() 194 | prefix = path[path.rfind("/")+1:path.rfind(".")] 195 | extens = path[path.rfind("."):] 196 | name = self.getOutputDir() + '/' + prefix + '-' + m.hexdigest() + extens 197 | try: 198 | f = open(name, "w+") 199 | f.write(raw) 200 | f.close() 201 | except: 202 | print "[-] Error: Can't write the file: %s" %(name) 203 | sys.exit(-1) 204 | self.__numSampleGen += 1 205 | 206 | def __genFile(self, raw, metadata): 207 | 208 | if self.getVerbose() == True: 209 | print "[+] Generating samples in progress..." 210 | 211 | generation = [] 212 | for elem in metadata: 213 | try: 214 | min = int(elem.split('[')[1].split(':')[0]) 215 | max = int(elem.split('[')[1].split(':')[1].split(']')[0]) 216 | generation += [[elem, min, max]] 217 | except: 218 | item = elem.split('[')[1].split(']')[0].split(",") 219 | generation += [[elem, item]] 220 | 221 | x = 0 222 | execEval = "" 223 | for elem in generation: 224 | if elem[0].find('__GENSTR') == 0: 225 | execEval += "%sfor i%d in range(len(generation[%d][1])):\n" %('\t' * x, x, x) 226 | elif elem[0].find('__GENINT') == 0: 227 | execEval += "%sfor i%d in range(generation[%d][1], generation[%d][2]+1):\n" %('\t' * x, x, x, x) 228 | x += 1 229 | execEval += "%sraw2 = raw\n" %('\t' * x) 230 | y = 0 231 | for elem in generation: 232 | if elem[0].find('__GENSTR') == 0: 233 | execEval += "%sraw2 = raw2.replace(r'%s', generation[%d][1][i%d])\n" %('\t' * x, elem[0], y, y) 234 | elif elem[0].find('__GENINTDEC') == 0: 235 | execEval += "%sraw2 = raw2.replace('%s', str(i%d))\n" %('\t' * x, elem[0], y) 236 | elif elem[0].find('__GENINTHEX') == 0: 237 | execEval += "%sraw2 = raw2.replace('%s', str(hex(i%d))[2:])\n" %('\t' * x, elem[0], y) 238 | y += 1 239 | execEval += "%sself.saveGeneratedFile(raw2)\n" %('\t' * y) 240 | exec(execEval) 241 | 242 | if self.getVerbose() == True: 243 | print "[+] Number of samples generated: %d" %(self.__numSampleGen) 244 | 245 | if __name__ == '__main__': 246 | 247 | metaSample = metaSample() 248 | metaSample.getOpt(sys.argv[1:]) 249 | metaSample.generate() 250 | 251 | sys.exit(0) 252 | 253 | -------------------------------------------------------------------------------- /triton/code_coverage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | ## 4 | ## Triton tool to perform code coverage 5 | ## Romain Thomas - 2015-09-26 6 | ## 7 | ## Description: 8 | ## ------------ 9 | ## 10 | ## This tool aims to reach all basic blocks in a program using dynamic symbolic 11 | ## resolution and the snapshot engine. The algorithm is based on Microsoft SAGE's 12 | ## fuzzer. 13 | ## 14 | ## 15 | ## Output: 16 | ## ------- 17 | ## 18 | ## $ ./triton ./src/tools/code_coverage.py ./src/samples/code_coverage/test_atoi a 19 | ## [+] Take Snapshot 20 | ## [+] In main 21 | ## [+] In main() we set : 22 | ## [0x7ffc92bdc54a] = 61 a 23 | ## [0x7ffc92bdc54b] = 61 a 24 | ## [0x7ffc92bdc54c] = 61 a 25 | ## [+] Exit point 26 | ## {140722770396490: 0} 27 | ## {140722770396490: 32} 28 | ## {140722770396490: 57} 29 | ## [+] Restore snapshot 30 | ## [+] In main 31 | ## [+] In main() we set : 32 | ## [0x7ffc92bdc54a] = 39 9 33 | ## [0x7ffc92bdc54b] = 61 a 34 | ## [0x7ffc92bdc54c] = 61 a 35 | ## [+] Exit point 36 | ## {140722770396490: 57, 140722770396491: 0} 37 | ## {140722770396490: 57, 140722770396491: 8} 38 | ## {140722770396490: 56, 140722770396491: 56} 39 | ## [+] Restore snapshot 40 | ## [+] In main 41 | ## [+] In main() we set : 42 | ## [0x7ffc92bdc54a] = 38 8 43 | ## [0x7ffc92bdc54b] = 38 8 44 | ## [0x7ffc92bdc54c] = 61 a 45 | ## [+] Exit point 46 | ## {140722770396490: 56, 140722770396491: 56, 140722770396492: 0} 47 | ## {140722770396490: 57, 140722770396491: 57, 140722770396492: 8} 48 | ## {140722770396490: 57, 140722770396491: 57, 140722770396492: 56} 49 | ## {140722770396490: 51, 140722770396491: 51, 140722770396492: 63} 50 | ## [+] Restore snapshot 51 | ## [+] In main 52 | ## [+] In main() we set : 53 | ## [0x7ffc92bdc54a] = 33 3 54 | ## [0x7ffc92bdc54b] = 33 3 55 | ## [0x7ffc92bdc54c] = 3f ? 56 | ## ok 57 | ## [+] Exit point 58 | ## [+] Done ! 59 | ## $ 60 | ## 61 | 62 | import ast 63 | 64 | from triton import * 65 | from pintool import * 66 | from collections import OrderedDict 67 | from copy import deepcopy 68 | 69 | 70 | 71 | class Input(object): 72 | 73 | def __init__(self, data): 74 | self.__data = data 75 | self.__bound = 0 76 | self.__dataAddr = dict() 77 | 78 | @property 79 | def data(self): 80 | return self.__data 81 | 82 | @property 83 | def bound(self): 84 | return self.__bound 85 | 86 | @property 87 | def dataAddr(self): 88 | return self.__dataAddr 89 | 90 | def setBound(self, bound): 91 | self.__bound = bound 92 | 93 | def addDataAddress(self, address, value): 94 | self.__dataAddr[address] = value 95 | 96 | 97 | 98 | class TritonExecution(object): 99 | 100 | program = None 101 | input = None 102 | worklist = None 103 | inputTested = None 104 | entryPoint = 0 105 | exitPoint = 0 106 | whitelist = None 107 | myPC = None 108 | AddrAfterEP = 0 109 | 110 | @staticmethod 111 | def cbefore(instruction): 112 | if instruction.getAddress() == TritonExecution.entryPoint: 113 | TritonExecution.AddrAfterEP = instruction.getNextAddress() 114 | 115 | if instruction.getAddress() == TritonExecution.AddrAfterEP: 116 | TritonExecution.myPC = [] # Reset the path constraint 117 | TritonExecution.input = TritonExecution.worklist.pop() # Take the first input 118 | TritonExecution.inputTested.append(TritonExecution.input) # Add this input to the tested input 119 | return 120 | 121 | if instruction.getAddress() == TritonExecution.entryPoint and not isSnapshotEnabled(): 122 | print "[+] Take Snapshot" 123 | takeSnapshot() 124 | return 125 | 126 | if getRoutineName(instruction.getAddress()) in TritonExecution.whitelist and instruction.isBranch() and instruction.getType() != OPCODE.JMP and instruction.getOperands()[0].getType() == OPERAND.IMM: 127 | addr1 = instruction.getNextAddress() # next address next from the current one 128 | addr2 = instruction.getOperands()[0].getValue() # Address in the instruction condition (branch taken) 129 | 130 | ripId = getSymbolicRegisterId(REG.RIP) # Get the reference of the RIP symbolic register 131 | 132 | # [PC id, address taken, address not taken] 133 | if instruction.isConditionTaken(): 134 | TritonExecution.myPC.append([ripId, addr2, addr1]) 135 | else: 136 | TritonExecution.myPC.append([ripId, addr1, addr2]) 137 | 138 | return 139 | 140 | if instruction.getAddress() == TritonExecution.exitPoint: 141 | print "[+] Exit point" 142 | 143 | # SAGE algorithm 144 | # http://research.microsoft.com/en-us/um/people/pg/public_psfiles/ndss2008.pdf 145 | for j in range(TritonExecution.input.bound, len(TritonExecution.myPC)): 146 | expr = [] 147 | for i in range(0,j): 148 | ripId = TritonExecution.myPC[i][0] 149 | symExp = getFullAst(getSymbolicExpressionFromId(ripId).getAst()) 150 | addr = TritonExecution.myPC[i][1] 151 | expr.append(ast.assert_(ast.equal(symExp, ast.bv(addr, CPUSIZE.QWORD_BIT)))) 152 | 153 | ripId = TritonExecution.myPC[j][0] 154 | symExp = getFullAst(getSymbolicExpressionFromId(ripId).getAst()) 155 | addr = TritonExecution.myPC[j][2] 156 | expr.append(ast.assert_(ast.equal(symExp, ast.bv(addr, CPUSIZE.QWORD_BIT)))) 157 | 158 | expr = ast.compound(expr) 159 | model = getModel(expr) 160 | 161 | if len(model) > 0: 162 | newInput = deepcopy(TritonExecution.input) 163 | newInput.setBound(j + 1) 164 | 165 | for k,v in model.items(): 166 | symVar = getSymbolicVariableFromId(k) 167 | newInput.addDataAddress(symVar.getKindValue(), v.getValue()) 168 | print newInput.dataAddr 169 | 170 | isPresent = False 171 | 172 | for inp in TritonExecution.worklist: 173 | if inp.dataAddr == newInput.dataAddr: 174 | isPresent = True 175 | break 176 | if not isPresent: 177 | TritonExecution.worklist.append(newInput) 178 | 179 | # If there is input to test in the worklist, we restore the snapshot 180 | if len(TritonExecution.worklist) > 0 and isSnapshotEnabled(): 181 | print "[+] Restore snapshot" 182 | restoreSnapshot() 183 | return 184 | return 185 | 186 | 187 | @staticmethod 188 | def fini(): 189 | print '[+] Done !' 190 | return 191 | 192 | 193 | @staticmethod 194 | def mainAnalysis(threadId): 195 | 196 | print "[+] In main" 197 | 198 | rdi = getCurrentRegisterValue(REG.RDI) # argc 199 | rsi = getCurrentRegisterValue(REG.RSI) # argv 200 | argv0_addr = getCurrentMemoryValue(getCurrentRegisterValue(REG.RSI), CPUSIZE.QWORD) # argv[0] pointer 201 | argv1_addr = getCurrentMemoryValue(rsi + CPUSIZE.QWORD, CPUSIZE.QWORD) # argv[1] pointer 202 | 203 | print "[+] In main() we set :" 204 | od = OrderedDict(sorted(TritonExecution.input.dataAddr.items())) 205 | 206 | for k,v in od.iteritems(): 207 | print "\t[0x%x] = %x %c" % (k, v, v) 208 | setCurrentMemoryValue(MemoryAccess(k, CPUSIZE.BYTE), v) 209 | convertMemoryToSymbolicVariable(MemoryAccess(k, CPUSIZE.BYTE), "addr_%d" % k) 210 | 211 | for idx, byte in enumerate(TritonExecution.input.data): 212 | if argv1_addr + idx not in TritonExecution.input.dataAddr: # Not overwrite the previous setting 213 | print "\t[0x%x] = %x %c" % (argv1_addr + idx, ord(byte), ord(byte)) 214 | setCurrentMemoryValue(MemoryAccess(argv1_addr + idx, CPUSIZE.BYTE), ord(byte)) 215 | convertMemoryToSymbolicVariable(MemoryAccess(argv1_addr + idx, CPUSIZE.BYTE), "addr_%d" % idx) 216 | 217 | 218 | @staticmethod 219 | def run(inputSeed, entryPoint, exitPoint, whitelist = []): 220 | 221 | TritonExecution.exitPoint = exitPoint 222 | TritonExecution.entryPoint = entryPoint 223 | TritonExecution.worklist = [Input(inputSeed)] 224 | TritonExecution.inputTested = [] 225 | TritonExecution.whitelist = whitelist 226 | 227 | startAnalysisFromAddress(entryPoint) 228 | 229 | insertCall(TritonExecution.mainAnalysis, INSERT_POINT.ROUTINE_ENTRY, "main") # Called when we are in main's beginning 230 | insertCall(TritonExecution.cbefore, INSERT_POINT.BEFORE) 231 | insertCall(TritonExecution.fini, INSERT_POINT.FINI) 232 | runProgram() 233 | 234 | 235 | 236 | if __name__=='__main__': 237 | # Set architecture 238 | setArchitecture(ARCH.X86_64) 239 | #TritonExecution.run("aaa", 0x4004a0, 0x40065D, ["main", "myatoi"]) # ./triton ./src/tools/code_coverage.py ./src/samples/code_coverage/test_atoi a 240 | #TritonExecution.run("bad !", 0x400480, 0x40061B, ["main", "check"]) # ./triton ./src/tools/code_coverage.py ./src/samples/crackmes/crackme_xor abc 241 | TritonExecution.run("aaaaaaaa", 0x400460, 0x400666, ["main", "check"]) # ./triton ./src/tools/code_coverage.py ./src/samples/crackmes/crackme_regex_fsm a 242 | #TritonExecution.run("aaaaaaaa", 0x400460, 0x402ECA, ["main", "checkinput"]) # ./triton ./src/tools/code_coverage.py ./src/samples/crackmes/crackme_regex_fsm_obfuscated a 243 | 244 | -------------------------------------------------------------------------------- /Taint_analysis_and_pattern_matching_with_Pin/Example-2-Spread-the-taint-in-memory-and-registers.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - Copyright (C) 2013-08 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Example 2 - http://shell-storm.org/blog/Taint-analysis-with-Pin/ 8 | // Spread the taint in memory and registers. 9 | // 10 | 11 | #include "pin.H" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | std::list addressTainted; 18 | std::list regsTainted; 19 | 20 | INT32 Usage() 21 | { 22 | cerr << "Ex 2" << endl; 23 | return -1; 24 | } 25 | 26 | bool checkAlreadyRegTainted(REG reg) 27 | { 28 | list::iterator i; 29 | 30 | for(i = regsTainted.begin(); i != regsTainted.end(); i++){ 31 | if (*i == reg){ 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | VOID removeMemTainted(UINT64 addr) 39 | { 40 | addressTainted.remove(addr); 41 | std::cout << std::hex << "\t\t\t" << addr << " is now freed" << std::endl; 42 | } 43 | 44 | VOID addMemTainted(UINT64 addr) 45 | { 46 | addressTainted.push_back(addr); 47 | std::cout << std::hex << "\t\t\t" << addr << " is now tainted" << std::endl; 48 | } 49 | 50 | bool taintReg(REG reg) 51 | { 52 | if (checkAlreadyRegTainted(reg) == true){ 53 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; 54 | return false; 55 | } 56 | 57 | switch(reg){ 58 | 59 | case REG_RAX: regsTainted.push_front(REG_RAX); 60 | case REG_EAX: regsTainted.push_front(REG_EAX); 61 | case REG_AX: regsTainted.push_front(REG_AX); 62 | case REG_AH: regsTainted.push_front(REG_AH); 63 | case REG_AL: regsTainted.push_front(REG_AL); 64 | break; 65 | 66 | case REG_RBX: regsTainted.push_front(REG_RBX); 67 | case REG_EBX: regsTainted.push_front(REG_EBX); 68 | case REG_BX: regsTainted.push_front(REG_BX); 69 | case REG_BH: regsTainted.push_front(REG_BH); 70 | case REG_BL: regsTainted.push_front(REG_BL); 71 | break; 72 | 73 | case REG_RCX: regsTainted.push_front(REG_RCX); 74 | case REG_ECX: regsTainted.push_front(REG_ECX); 75 | case REG_CX: regsTainted.push_front(REG_CX); 76 | case REG_CH: regsTainted.push_front(REG_CH); 77 | case REG_CL: regsTainted.push_front(REG_CL); 78 | break; 79 | 80 | case REG_RDX: regsTainted.push_front(REG_RDX); 81 | case REG_EDX: regsTainted.push_front(REG_EDX); 82 | case REG_DX: regsTainted.push_front(REG_DX); 83 | case REG_DH: regsTainted.push_front(REG_DH); 84 | case REG_DL: regsTainted.push_front(REG_DL); 85 | break; 86 | 87 | case REG_RDI: regsTainted.push_front(REG_RDI); 88 | case REG_EDI: regsTainted.push_front(REG_EDI); 89 | case REG_DI: regsTainted.push_front(REG_DI); 90 | case REG_DIL: regsTainted.push_front(REG_DIL); 91 | break; 92 | 93 | case REG_RSI: regsTainted.push_front(REG_RSI); 94 | case REG_ESI: regsTainted.push_front(REG_ESI); 95 | case REG_SI: regsTainted.push_front(REG_SI); 96 | case REG_SIL: regsTainted.push_front(REG_SIL); 97 | break; 98 | 99 | default: 100 | std::cout << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; 101 | return false; 102 | } 103 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; 104 | return true; 105 | } 106 | 107 | bool removeRegTainted(REG reg) 108 | { 109 | switch(reg){ 110 | 111 | case REG_RAX: regsTainted.remove(REG_RAX); 112 | case REG_EAX: regsTainted.remove(REG_EAX); 113 | case REG_AX: regsTainted.remove(REG_AX); 114 | case REG_AH: regsTainted.remove(REG_AH); 115 | case REG_AL: regsTainted.remove(REG_AL); 116 | break; 117 | 118 | case REG_RBX: regsTainted.remove(REG_RBX); 119 | case REG_EBX: regsTainted.remove(REG_EBX); 120 | case REG_BX: regsTainted.remove(REG_BX); 121 | case REG_BH: regsTainted.remove(REG_BH); 122 | case REG_BL: regsTainted.remove(REG_BL); 123 | break; 124 | 125 | case REG_RCX: regsTainted.remove(REG_RCX); 126 | case REG_ECX: regsTainted.remove(REG_ECX); 127 | case REG_CX: regsTainted.remove(REG_CX); 128 | case REG_CH: regsTainted.remove(REG_CH); 129 | case REG_CL: regsTainted.remove(REG_CL); 130 | break; 131 | 132 | case REG_RDX: regsTainted.remove(REG_RDX); 133 | case REG_EDX: regsTainted.remove(REG_EDX); 134 | case REG_DX: regsTainted.remove(REG_DX); 135 | case REG_DH: regsTainted.remove(REG_DH); 136 | case REG_DL: regsTainted.remove(REG_DL); 137 | break; 138 | 139 | case REG_RDI: regsTainted.remove(REG_RDI); 140 | case REG_EDI: regsTainted.remove(REG_EDI); 141 | case REG_DI: regsTainted.remove(REG_DI); 142 | case REG_DIL: regsTainted.remove(REG_DIL); 143 | break; 144 | 145 | case REG_RSI: regsTainted.remove(REG_RSI); 146 | case REG_ESI: regsTainted.remove(REG_ESI); 147 | case REG_SI: regsTainted.remove(REG_SI); 148 | case REG_SIL: regsTainted.remove(REG_SIL); 149 | break; 150 | 151 | default: 152 | return false; 153 | } 154 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; 155 | return true; 156 | } 157 | 158 | VOID ReadMem(INS ins, UINT64 memOp) 159 | { 160 | list::iterator i; 161 | UINT64 addr = memOp; 162 | REG reg_r; 163 | 164 | if (INS_OperandCount(ins) != 2) 165 | return; 166 | 167 | reg_r = INS_OperandReg(ins, 0); 168 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 169 | if (addr == *i){ 170 | std::cout << std::hex << "[READ in " << addr << "]\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; 171 | taintReg(reg_r); 172 | return ; 173 | } 174 | } 175 | /* if mem != tained and reg == taint => free the reg */ 176 | if (checkAlreadyRegTainted(reg_r)){ 177 | std::cout << std::hex << "[READ in " << addr << "]\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; 178 | removeRegTainted(reg_r); 179 | } 180 | } 181 | 182 | VOID WriteMem(INS ins, UINT64 memOp) 183 | { 184 | list::iterator i; 185 | UINT64 addr = memOp; 186 | REG reg_r; 187 | 188 | if (INS_OperandCount(ins) != 2) 189 | return; 190 | 191 | reg_r = INS_OperandReg(ins, 1); 192 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 193 | if (addr == *i){ 194 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; 195 | if (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r)) 196 | removeMemTainted(addr); 197 | return ; 198 | } 199 | } 200 | if (checkAlreadyRegTainted(reg_r)){ 201 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; 202 | addMemTainted(addr); 203 | } 204 | } 205 | 206 | VOID spreadRegTaint(INS ins) 207 | { 208 | REG reg_r, reg_w; 209 | 210 | if (INS_OperandCount(ins) != 2) 211 | return; 212 | 213 | reg_r = INS_RegR(ins, 0); 214 | reg_w = INS_RegW(ins, 0); 215 | 216 | if (REG_valid(reg_w)){ 217 | if (checkAlreadyRegTainted(reg_w) && (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r))){ 218 | std::cout << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; 219 | std::cout << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; 220 | removeRegTainted(reg_w); 221 | } 222 | else if (!checkAlreadyRegTainted(reg_w) && checkAlreadyRegTainted(reg_r)){ 223 | std::cout << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl; 224 | std::cout << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; 225 | taintReg(reg_w); 226 | } 227 | } 228 | } 229 | 230 | VOID Instruction(INS ins, VOID *v) 231 | { 232 | if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 233 | INS_InsertCall( 234 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 235 | IARG_PTR, ins, 236 | IARG_MEMORYOP_EA, 0, 237 | IARG_END); 238 | } 239 | else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ 240 | INS_InsertCall( 241 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 242 | IARG_PTR, ins, 243 | IARG_MEMORYOP_EA, 0, 244 | IARG_END); 245 | } 246 | else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 247 | INS_InsertCall( 248 | ins, IPOINT_BEFORE, (AFUNPTR)spreadRegTaint, 249 | IARG_PTR, ins, 250 | IARG_END); 251 | } 252 | } 253 | 254 | static unsigned int tryksOpen; 255 | 256 | #define TRICKS(){if (tryksOpen++ == 0)return;} 257 | 258 | VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 259 | { 260 | unsigned int i; 261 | UINT64 start, size; 262 | 263 | if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ 264 | 265 | TRICKS(); /* tricks to ignore the first open */ 266 | 267 | start = static_cast((PIN_GetSyscallArgument(ctx, std, 1))); 268 | size = static_cast((PIN_GetSyscallArgument(ctx, std, 2))); 269 | 270 | for (i = 0; i < size; i++) 271 | addressTainted.push_back(start+i); 272 | 273 | std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << start << " to 0x" << start+size << " (via read)"<< std::endl; 274 | } 275 | } 276 | 277 | int main(int argc, char *argv[]) 278 | { 279 | if(PIN_Init(argc, argv)){ 280 | return Usage(); 281 | } 282 | 283 | PIN_SetSyntaxIntel(); 284 | PIN_AddSyscallEntryFunction(Syscall_entry, 0); 285 | INS_AddInstrumentFunction(Instruction, 0); 286 | PIN_StartProgram(); 287 | 288 | return 0; 289 | } 290 | 291 | -------------------------------------------------------------------------------- /Taint_analysis_and_pattern_matching_with_Pin/Example-3-Spread-the-taint-and-follow-your-data.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - Copyright (C) 2013-08 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Example 3 - http://shell-storm.org/blog/Taint-analysis-with-Pin/ 8 | // Spread the taint in memory/registers and follow your data. 9 | // 10 | 11 | #include "pin.H" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | std::list addressTainted; 18 | std::list regsTainted; 19 | 20 | INT32 Usage() 21 | { 22 | cerr << "Ex 3" << endl; 23 | return -1; 24 | } 25 | 26 | bool checkAlreadyRegTainted(REG reg) 27 | { 28 | list::iterator i; 29 | 30 | for(i = regsTainted.begin(); i != regsTainted.end(); i++){ 31 | if (*i == reg){ 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | VOID removeMemTainted(UINT64 addr) 39 | { 40 | addressTainted.remove(addr); 41 | std::cout << std::hex << "\t\t\t" << addr << " is now freed" << std::endl; 42 | } 43 | 44 | VOID addMemTainted(UINT64 addr) 45 | { 46 | addressTainted.push_back(addr); 47 | std::cout << std::hex << "\t\t\t" << addr << " is now tainted" << std::endl; 48 | } 49 | 50 | bool taintReg(REG reg) 51 | { 52 | if (checkAlreadyRegTainted(reg) == true){ 53 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; 54 | return false; 55 | } 56 | 57 | switch(reg){ 58 | 59 | case REG_RAX: regsTainted.push_front(REG_RAX); 60 | case REG_EAX: regsTainted.push_front(REG_EAX); 61 | case REG_AX: regsTainted.push_front(REG_AX); 62 | case REG_AH: regsTainted.push_front(REG_AH); 63 | case REG_AL: regsTainted.push_front(REG_AL); 64 | break; 65 | 66 | case REG_RBX: regsTainted.push_front(REG_RBX); 67 | case REG_EBX: regsTainted.push_front(REG_EBX); 68 | case REG_BX: regsTainted.push_front(REG_BX); 69 | case REG_BH: regsTainted.push_front(REG_BH); 70 | case REG_BL: regsTainted.push_front(REG_BL); 71 | break; 72 | 73 | case REG_RCX: regsTainted.push_front(REG_RCX); 74 | case REG_ECX: regsTainted.push_front(REG_ECX); 75 | case REG_CX: regsTainted.push_front(REG_CX); 76 | case REG_CH: regsTainted.push_front(REG_CH); 77 | case REG_CL: regsTainted.push_front(REG_CL); 78 | break; 79 | 80 | case REG_RDX: regsTainted.push_front(REG_RDX); 81 | case REG_EDX: regsTainted.push_front(REG_EDX); 82 | case REG_DX: regsTainted.push_front(REG_DX); 83 | case REG_DH: regsTainted.push_front(REG_DH); 84 | case REG_DL: regsTainted.push_front(REG_DL); 85 | break; 86 | 87 | case REG_RDI: regsTainted.push_front(REG_RDI); 88 | case REG_EDI: regsTainted.push_front(REG_EDI); 89 | case REG_DI: regsTainted.push_front(REG_DI); 90 | case REG_DIL: regsTainted.push_front(REG_DIL); 91 | break; 92 | 93 | case REG_RSI: regsTainted.push_front(REG_RSI); 94 | case REG_ESI: regsTainted.push_front(REG_ESI); 95 | case REG_SI: regsTainted.push_front(REG_SI); 96 | case REG_SIL: regsTainted.push_front(REG_SIL); 97 | break; 98 | 99 | default: 100 | std::cout << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; 101 | return false; 102 | } 103 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; 104 | return true; 105 | } 106 | 107 | bool removeRegTainted(REG reg) 108 | { 109 | switch(reg){ 110 | 111 | case REG_RAX: regsTainted.remove(REG_RAX); 112 | case REG_EAX: regsTainted.remove(REG_EAX); 113 | case REG_AX: regsTainted.remove(REG_AX); 114 | case REG_AH: regsTainted.remove(REG_AH); 115 | case REG_AL: regsTainted.remove(REG_AL); 116 | break; 117 | 118 | case REG_RBX: regsTainted.remove(REG_RBX); 119 | case REG_EBX: regsTainted.remove(REG_EBX); 120 | case REG_BX: regsTainted.remove(REG_BX); 121 | case REG_BH: regsTainted.remove(REG_BH); 122 | case REG_BL: regsTainted.remove(REG_BL); 123 | break; 124 | 125 | case REG_RCX: regsTainted.remove(REG_RCX); 126 | case REG_ECX: regsTainted.remove(REG_ECX); 127 | case REG_CX: regsTainted.remove(REG_CX); 128 | case REG_CH: regsTainted.remove(REG_CH); 129 | case REG_CL: regsTainted.remove(REG_CL); 130 | break; 131 | 132 | case REG_RDX: regsTainted.remove(REG_RDX); 133 | case REG_EDX: regsTainted.remove(REG_EDX); 134 | case REG_DX: regsTainted.remove(REG_DX); 135 | case REG_DH: regsTainted.remove(REG_DH); 136 | case REG_DL: regsTainted.remove(REG_DL); 137 | break; 138 | 139 | case REG_RDI: regsTainted.remove(REG_RDI); 140 | case REG_EDI: regsTainted.remove(REG_EDI); 141 | case REG_DI: regsTainted.remove(REG_DI); 142 | case REG_DIL: regsTainted.remove(REG_DIL); 143 | break; 144 | 145 | case REG_RSI: regsTainted.remove(REG_RSI); 146 | case REG_ESI: regsTainted.remove(REG_ESI); 147 | case REG_SI: regsTainted.remove(REG_SI); 148 | case REG_SIL: regsTainted.remove(REG_SIL); 149 | break; 150 | 151 | default: 152 | return false; 153 | } 154 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; 155 | return true; 156 | } 157 | 158 | VOID ReadMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp) 159 | { 160 | list::iterator i; 161 | UINT64 addr = memOp; 162 | 163 | if (opCount != 2) 164 | return; 165 | 166 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 167 | if (addr == *i){ 168 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 169 | taintReg(reg_r); 170 | return ; 171 | } 172 | } 173 | /* if mem != tained and reg == taint => free the reg */ 174 | if (checkAlreadyRegTainted(reg_r)){ 175 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 176 | removeRegTainted(reg_r); 177 | } 178 | } 179 | 180 | VOID WriteMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp) 181 | { 182 | list::iterator i; 183 | UINT64 addr = memOp; 184 | 185 | if (opCount != 2) 186 | return; 187 | 188 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 189 | if (addr == *i){ 190 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 191 | if (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r)) 192 | removeMemTainted(addr); 193 | return ; 194 | } 195 | } 196 | if (checkAlreadyRegTainted(reg_r)){ 197 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 198 | addMemTainted(addr); 199 | } 200 | } 201 | 202 | VOID spreadRegTaint(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, REG reg_w) 203 | { 204 | if (opCount != 2) 205 | return; 206 | 207 | if (REG_valid(reg_w)){ 208 | if (checkAlreadyRegTainted(reg_w) && (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r))){ 209 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 210 | std::cout << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; 211 | removeRegTainted(reg_w); 212 | } 213 | else if (!checkAlreadyRegTainted(reg_w) && checkAlreadyRegTainted(reg_r)){ 214 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 215 | std::cout << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; 216 | taintReg(reg_w); 217 | } 218 | } 219 | } 220 | 221 | VOID followData(UINT64 insAddr, std::string insDis, REG reg) 222 | { 223 | if (!REG_valid(reg)) 224 | return; 225 | 226 | if (checkAlreadyRegTainted(reg)){ 227 | std::cout << "[FOLLOW]\t\t" << insAddr << ": " << insDis << std::endl; 228 | } 229 | } 230 | 231 | VOID Instruction(INS ins, VOID *v) 232 | { 233 | if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 234 | INS_InsertCall( 235 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 236 | IARG_ADDRINT, INS_Address(ins), 237 | IARG_PTR, new string(INS_Disassemble(ins)), 238 | IARG_UINT32, INS_OperandCount(ins), 239 | IARG_UINT32, INS_OperandReg(ins, 0), 240 | IARG_MEMORYOP_EA, 0, 241 | IARG_END); 242 | } 243 | else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ 244 | INS_InsertCall( 245 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 246 | IARG_ADDRINT, INS_Address(ins), 247 | IARG_PTR, new string(INS_Disassemble(ins)), 248 | IARG_UINT32, INS_OperandCount(ins), 249 | IARG_UINT32, INS_OperandReg(ins, 1), 250 | IARG_MEMORYOP_EA, 0, 251 | IARG_END); 252 | } 253 | else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 254 | INS_InsertCall( 255 | ins, IPOINT_BEFORE, (AFUNPTR)spreadRegTaint, 256 | IARG_ADDRINT, INS_Address(ins), 257 | IARG_PTR, new string(INS_Disassemble(ins)), 258 | IARG_UINT32, INS_OperandCount(ins), 259 | IARG_UINT32, INS_RegR(ins, 0), 260 | IARG_UINT32, INS_RegW(ins, 0), 261 | IARG_END); 262 | } 263 | 264 | if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 265 | INS_InsertCall( 266 | ins, IPOINT_BEFORE, (AFUNPTR)followData, 267 | IARG_ADDRINT, INS_Address(ins), 268 | IARG_PTR, new string(INS_Disassemble(ins)), 269 | IARG_UINT32, INS_RegR(ins, 0), 270 | IARG_END); 271 | } 272 | } 273 | 274 | static unsigned int tryksOpen; 275 | 276 | #define TRICKS(){if (tryksOpen++ == 0)return;} 277 | 278 | VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 279 | { 280 | unsigned int i; 281 | UINT64 start, size; 282 | 283 | if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ 284 | 285 | TRICKS(); /* tricks to ignore the first open */ 286 | 287 | start = static_cast((PIN_GetSyscallArgument(ctx, std, 1))); 288 | size = static_cast((PIN_GetSyscallArgument(ctx, std, 2))); 289 | 290 | for (i = 0; i < size; i++) 291 | addressTainted.push_back(start+i); 292 | 293 | std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << start << " to 0x" << start+size << " (via read)"<< std::endl; 294 | } 295 | } 296 | 297 | int main(int argc, char *argv[]) 298 | { 299 | if(PIN_Init(argc, argv)){ 300 | return Usage(); 301 | } 302 | 303 | PIN_SetSyntaxIntel(); 304 | PIN_AddSyscallEntryFunction(Syscall_entry, 0); 305 | INS_AddInstrumentFunction(Instruction, 0); 306 | PIN_StartProgram(); 307 | 308 | return 0; 309 | } 310 | 311 | -------------------------------------------------------------------------------- /Taint_analysis_and_pattern_matching_with_Pin/Example-4-Obsolete-stack-frame-access-detection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - Copyright (C) 2013-08 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Example 4 - http://shell-storm.org/blog/Taint-analysis-with-Pin/ 8 | // Detect a use after free vulnerability via a old stack frame 9 | // 10 | 11 | #include "pin.H" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | std::list addressTainted; 18 | std::list regsTainted; 19 | 20 | INT32 Usage() 21 | { 22 | cerr << "Ex 4" << endl; 23 | return -1; 24 | } 25 | 26 | bool checkAlreadyRegTainted(REG reg) 27 | { 28 | list::iterator i; 29 | 30 | for(i = regsTainted.begin(); i != regsTainted.end(); i++){ 31 | if (*i == reg){ 32 | return true; 33 | } 34 | } 35 | return false; 36 | } 37 | 38 | VOID removeMemTainted(UINT64 addr) 39 | { 40 | addressTainted.remove(addr); 41 | std::cout << std::hex << "\t\t\t" << addr << " is now freed" << std::endl; 42 | } 43 | 44 | VOID addMemTainted(UINT64 addr) 45 | { 46 | addressTainted.push_back(addr); 47 | std::cout << std::hex << "\t\t\t" << addr << " is now tainted" << std::endl; 48 | } 49 | 50 | bool taintReg(REG reg) 51 | { 52 | if (checkAlreadyRegTainted(reg) == true){ 53 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; 54 | return false; 55 | } 56 | 57 | switch(reg){ 58 | 59 | case REG_RAX: regsTainted.push_front(REG_RAX); 60 | case REG_EAX: regsTainted.push_front(REG_EAX); 61 | case REG_AX: regsTainted.push_front(REG_AX); 62 | case REG_AH: regsTainted.push_front(REG_AH); 63 | case REG_AL: regsTainted.push_front(REG_AL); 64 | break; 65 | 66 | case REG_RBX: regsTainted.push_front(REG_RBX); 67 | case REG_EBX: regsTainted.push_front(REG_EBX); 68 | case REG_BX: regsTainted.push_front(REG_BX); 69 | case REG_BH: regsTainted.push_front(REG_BH); 70 | case REG_BL: regsTainted.push_front(REG_BL); 71 | break; 72 | 73 | case REG_RCX: regsTainted.push_front(REG_RCX); 74 | case REG_ECX: regsTainted.push_front(REG_ECX); 75 | case REG_CX: regsTainted.push_front(REG_CX); 76 | case REG_CH: regsTainted.push_front(REG_CH); 77 | case REG_CL: regsTainted.push_front(REG_CL); 78 | break; 79 | 80 | case REG_RDX: regsTainted.push_front(REG_RDX); 81 | case REG_EDX: regsTainted.push_front(REG_EDX); 82 | case REG_DX: regsTainted.push_front(REG_DX); 83 | case REG_DH: regsTainted.push_front(REG_DH); 84 | case REG_DL: regsTainted.push_front(REG_DL); 85 | break; 86 | 87 | case REG_RDI: regsTainted.push_front(REG_RDI); 88 | case REG_EDI: regsTainted.push_front(REG_EDI); 89 | case REG_DI: regsTainted.push_front(REG_DI); 90 | case REG_DIL: regsTainted.push_front(REG_DIL); 91 | break; 92 | 93 | case REG_RSI: regsTainted.push_front(REG_RSI); 94 | case REG_ESI: regsTainted.push_front(REG_ESI); 95 | case REG_SI: regsTainted.push_front(REG_SI); 96 | case REG_SIL: regsTainted.push_front(REG_SIL); 97 | break; 98 | 99 | default: 100 | std::cout << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; 101 | return false; 102 | } 103 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; 104 | return true; 105 | } 106 | 107 | bool removeRegTainted(REG reg) 108 | { 109 | switch(reg){ 110 | 111 | case REG_RAX: regsTainted.remove(REG_RAX); 112 | case REG_EAX: regsTainted.remove(REG_EAX); 113 | case REG_AX: regsTainted.remove(REG_AX); 114 | case REG_AH: regsTainted.remove(REG_AH); 115 | case REG_AL: regsTainted.remove(REG_AL); 116 | break; 117 | 118 | case REG_RBX: regsTainted.remove(REG_RBX); 119 | case REG_EBX: regsTainted.remove(REG_EBX); 120 | case REG_BX: regsTainted.remove(REG_BX); 121 | case REG_BH: regsTainted.remove(REG_BH); 122 | case REG_BL: regsTainted.remove(REG_BL); 123 | break; 124 | 125 | case REG_RCX: regsTainted.remove(REG_RCX); 126 | case REG_ECX: regsTainted.remove(REG_ECX); 127 | case REG_CX: regsTainted.remove(REG_CX); 128 | case REG_CH: regsTainted.remove(REG_CH); 129 | case REG_CL: regsTainted.remove(REG_CL); 130 | break; 131 | 132 | case REG_RDX: regsTainted.remove(REG_RDX); 133 | case REG_EDX: regsTainted.remove(REG_EDX); 134 | case REG_DX: regsTainted.remove(REG_DX); 135 | case REG_DH: regsTainted.remove(REG_DH); 136 | case REG_DL: regsTainted.remove(REG_DL); 137 | break; 138 | 139 | case REG_RDI: regsTainted.remove(REG_RDI); 140 | case REG_EDI: regsTainted.remove(REG_EDI); 141 | case REG_DI: regsTainted.remove(REG_DI); 142 | case REG_DIL: regsTainted.remove(REG_DIL); 143 | break; 144 | 145 | case REG_RSI: regsTainted.remove(REG_RSI); 146 | case REG_ESI: regsTainted.remove(REG_ESI); 147 | case REG_SI: regsTainted.remove(REG_SI); 148 | case REG_SIL: regsTainted.remove(REG_SIL); 149 | break; 150 | 151 | default: 152 | return false; 153 | } 154 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; 155 | return true; 156 | } 157 | 158 | VOID ReadMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp, UINT64 sp) 159 | { 160 | list::iterator i; 161 | UINT64 addr = memOp; 162 | 163 | if (opCount != 2) 164 | return; 165 | 166 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 167 | if (addr == *i){ 168 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 169 | taintReg(reg_r); 170 | 171 | if (sp > addr && addr > 0x700000000000) 172 | std::cout << std::hex << "[UAF in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 173 | 174 | return ; 175 | } 176 | } 177 | /* if mem != tained and reg == taint => free the reg */ 178 | if (checkAlreadyRegTainted(reg_r)){ 179 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 180 | removeRegTainted(reg_r); 181 | } 182 | } 183 | 184 | VOID WriteMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp, UINT64 sp) 185 | { 186 | list::iterator i; 187 | UINT64 addr = memOp; 188 | 189 | if (opCount != 2) 190 | return; 191 | 192 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 193 | if (addr == *i){ 194 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 195 | if (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r)) 196 | removeMemTainted(addr); 197 | 198 | if (sp > addr && addr > 0x700000000000) 199 | std::cout << std::hex << "[UAF in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 200 | 201 | return ; 202 | } 203 | } 204 | if (checkAlreadyRegTainted(reg_r)){ 205 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 206 | addMemTainted(addr); 207 | } 208 | } 209 | 210 | VOID spreadRegTaint(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, REG reg_w) 211 | { 212 | if (opCount != 2) 213 | return; 214 | 215 | if (REG_valid(reg_w)){ 216 | if (checkAlreadyRegTainted(reg_w) && (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r))){ 217 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 218 | std::cout << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; 219 | removeRegTainted(reg_w); 220 | } 221 | else if (!checkAlreadyRegTainted(reg_w) && checkAlreadyRegTainted(reg_r)){ 222 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 223 | std::cout << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; 224 | taintReg(reg_w); 225 | } 226 | } 227 | } 228 | 229 | VOID followData(UINT64 insAddr, std::string insDis, REG reg) 230 | { 231 | if (!REG_valid(reg)) 232 | return; 233 | 234 | if (checkAlreadyRegTainted(reg)){ 235 | std::cout << "[FOLLOW]\t\t" << insAddr << ": " << insDis << std::endl; 236 | } 237 | } 238 | 239 | VOID Instruction(INS ins, VOID *v) 240 | { 241 | if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 242 | INS_InsertCall( 243 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 244 | IARG_ADDRINT, INS_Address(ins), 245 | IARG_PTR, new string(INS_Disassemble(ins)), 246 | IARG_UINT32, INS_OperandCount(ins), 247 | IARG_UINT32, INS_OperandReg(ins, 0), 248 | IARG_MEMORYOP_EA, 0, 249 | IARG_REG_VALUE, REG_STACK_PTR, 250 | IARG_END); 251 | } 252 | else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ 253 | INS_InsertCall( 254 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 255 | IARG_ADDRINT, INS_Address(ins), 256 | IARG_PTR, new string(INS_Disassemble(ins)), 257 | IARG_UINT32, INS_OperandCount(ins), 258 | IARG_UINT32, INS_OperandReg(ins, 1), 259 | IARG_MEMORYOP_EA, 0, 260 | IARG_REG_VALUE, REG_STACK_PTR, 261 | IARG_END); 262 | } 263 | else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 264 | INS_InsertCall( 265 | ins, IPOINT_BEFORE, (AFUNPTR)spreadRegTaint, 266 | IARG_ADDRINT, INS_Address(ins), 267 | IARG_PTR, new string(INS_Disassemble(ins)), 268 | IARG_UINT32, INS_OperandCount(ins), 269 | IARG_UINT32, INS_RegR(ins, 0), 270 | IARG_UINT32, INS_RegW(ins, 0), 271 | IARG_END); 272 | } 273 | 274 | if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 275 | INS_InsertCall( 276 | ins, IPOINT_BEFORE, (AFUNPTR)followData, 277 | IARG_ADDRINT, INS_Address(ins), 278 | IARG_PTR, new string(INS_Disassemble(ins)), 279 | IARG_UINT32, INS_RegR(ins, 0), 280 | IARG_END); 281 | } 282 | } 283 | 284 | static unsigned int tryksOpen; 285 | 286 | #define TRICKS(){if (tryksOpen++ == 0)return;} 287 | 288 | VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 289 | { 290 | unsigned int i; 291 | UINT64 start, size; 292 | 293 | if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ 294 | 295 | TRICKS(); /* tricks to ignore the first open */ 296 | 297 | start = static_cast((PIN_GetSyscallArgument(ctx, std, 1))); 298 | size = static_cast((PIN_GetSyscallArgument(ctx, std, 2))); 299 | 300 | for (i = 0; i < size; i++) 301 | addressTainted.push_back(start+i); 302 | 303 | std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << start << " to 0x" << start+size << " (via read)"<< std::endl; 304 | } 305 | } 306 | 307 | int main(int argc, char *argv[]) 308 | { 309 | if(PIN_Init(argc, argv)){ 310 | return Usage(); 311 | } 312 | 313 | PIN_SetSyntaxIntel(); 314 | PIN_AddSyscallEntryFunction(Syscall_entry, 0); 315 | INS_AddInstrumentFunction(Instruction, 0); 316 | PIN_StartProgram(); 317 | 318 | return 0; 319 | } 320 | 321 | -------------------------------------------------------------------------------- /Pin-tool-InMemoryFuzzing.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BEGIN_LEGAL 3 | // Intel Open Source License 4 | // 5 | // Copyright (c) 2002-2013 Intel Corporation. All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are 9 | // met: 10 | // 11 | // Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. Redistributions 13 | // in binary form must reproduce the above copyright notice, this list of 14 | // conditions and the following disclaimer in the documentation and/or 15 | // other materials provided with the distribution. Neither the name of 16 | // the Intel Corporation nor the names of its contributors may be used to 17 | // endorse or promote products derived from this software without 18 | // specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR 24 | // ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // END_LEGAL 32 | // 33 | // ------------------------------------------------------------------------ 34 | // 35 | // Jonathan Salwan - 2013-08-17 36 | // 37 | // http://shell-storm.org 38 | // http://twitter.com/JonathanSalwan 39 | // 40 | // Note: In-Memory Fuzzing with Pin 41 | // http://shell-storm.org/blog/In-Memory-fuzzing-with-Pin/ 42 | // 43 | // Vulnerable example: 44 | // 45 | // 400584 : 46 | // 400584: 55 push rbp 47 | // 400585: 48 89 e5 mov rbp,rsp 48 | // 400588: 48 83 ec 10 sub rsp,0x10 49 | // 40058c: 89 7d fc mov DWORD PTR [rbp-0x4],edi 50 | // 40058f: 48 89 75 f0 mov QWORD PTR [rbp-0x10],rsi 51 | // 400593: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 52 | // 400596: 48 98 cdqe 53 | // 400598: 48 03 45 f0 add rax,QWORD PTR [rbp-0x10] 54 | // 40059c: 0f b6 00 movzx eax,BYTE PTR [rax] 55 | // 40059f: 0f be d0 movsx edx,al 56 | // 4005a2: b8 2c 07 40 00 mov eax,0x40072c 57 | // 4005a7: 89 d6 mov esi,edx 58 | // 4005a9: 48 89 c7 mov rdi,rax 59 | // 4005ac: b8 00 00 00 00 mov eax,0x0 60 | // 4005b1: e8 ba fe ff ff call 400470 61 | // 4005b6: c9 leave 62 | // 4005b7: c3 ret 63 | // 64 | // Syntax based on the above code: 65 | // $ ../../../pin -t ./obj-intel64/InMemoryFuzzing.so -start 0x400584 -end 0x4005b7 -reg rdi -fuzzingType inc -maxValue 0x3000 -- ./test 1 66 | // 67 | // The output will be like that: 68 | // [...] 69 | // [Save Context] 70 | // [CONTEXT]=---------------------------------------------------------- 71 | // RAX = 0000000000000002 RBX = 0000000000000000 RCX = 00007fffb8f55170 72 | // RDX = 00007fffb8f542e0 RDI = 0000000000001d20 RSI = 00007fffb8f542e0 73 | // RBP = 00007fffb8f54310 RSP = 00007fffb8f542c8 RIP = 0000000000400585 74 | // +------------------------------------------------------------------- 75 | // +--> 400585: mov rbp, rsp 76 | // +--> 400588: sub rsp, 0x10 77 | // +--> 40058c: mov dword ptr [rbp-0x4], edi 78 | // +--> 40058f: mov qword ptr [rbp-0x10], rsi 79 | // +--> 400593: mov eax, dword ptr [rbp-0x4] 80 | // +--> 400596: cdqe 81 | // +--> 400598: add rax, qword ptr [rbp-0x10] 82 | // +--> 40059c: movzx eax, byte ptr [rax] 83 | // 84 | // SIGSEGV received 85 | // [SIGSGV]=---------------------------------------------------------- 86 | // RAX = 00007fffb8f56000 RBX = 0000000000000000 RCX = 00007fffb8f55170 87 | // RDX = 00007fffb8f542e0 RDI = 0000000000001d20 RSI = 00007fffb8f542e0 88 | // RBP = 00007fffb8f542c8 RSP = 00007fffb8f542b8 RIP = 000000000040059c 89 | // +------------------------------------------------------------------- 90 | // 91 | // 92 | // We got a SIGSEGV if RDI = 0x1d20 93 | // 94 | 95 | #include "pin.H" 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | 105 | #define LOCKED 1 106 | #define UNLOCKED !LOCKED 107 | 108 | #define CONTEXT_FLG 0 109 | #define SIGSEGV_FLG 1 110 | 111 | struct memoryInput 112 | { 113 | ADDRINT address; 114 | UINT64 value; 115 | }; 116 | 117 | struct regRef 118 | { 119 | std::string name; 120 | LEVEL_BASE::REG ref; 121 | }; 122 | 123 | static UINT32 _lock = LOCKED; 124 | std::list memInput; 125 | CONTEXT snapshot; 126 | 127 | /* Required arg */ 128 | KNOB KnobStart(KNOB_MODE_WRITEONCE, "pintool", "start", "0", "The start address of the fuzzing area"); 129 | KNOB KnobEnd(KNOB_MODE_WRITEONCE, "pintool", "end", "0", "The end address of the fuzzing area"); 130 | KNOB KnobREG(KNOB_MODE_WRITEONCE, "pintool", "reg", "none", "The register which will be fuzzed"); 131 | 132 | /* Optinal arg */ 133 | KNOB KnobStartValue(KNOB_MODE_WRITEONCE, "pintool", "startValue", "0", "The start value"); 134 | KNOB KnobMaxValue(KNOB_MODE_WRITEONCE, "pintool", "maxValue", "0xffffffff", "The end value"); 135 | KNOB KnobFuzzType(KNOB_MODE_WRITEONCE, "pintool", "fuzzingType", "none", "Type of fuzzing: incremental or random"); 136 | 137 | static struct regRef regsRef[] = 138 | { 139 | {"rax", LEVEL_BASE::REG_RAX}, 140 | {"rbx", LEVEL_BASE::REG_RBX}, 141 | {"rcx", LEVEL_BASE::REG_RCX}, 142 | {"rdx", LEVEL_BASE::REG_RDX}, 143 | {"rdi", LEVEL_BASE::REG_RDI}, 144 | {"rsi", LEVEL_BASE::REG_RSI}, 145 | {"eax", LEVEL_BASE::REG_EAX}, 146 | {"ebx", LEVEL_BASE::REG_EBX}, 147 | {"ecx", LEVEL_BASE::REG_ECX}, 148 | {"edx", LEVEL_BASE::REG_EDX}, 149 | {"edi", LEVEL_BASE::REG_EDI}, 150 | {"esi", LEVEL_BASE::REG_ESI}, 151 | {"ah", LEVEL_BASE::REG_AH}, 152 | {"bh", LEVEL_BASE::REG_BH}, 153 | {"ch", LEVEL_BASE::REG_CH}, 154 | {"dh", LEVEL_BASE::REG_DH}, 155 | {"al", LEVEL_BASE::REG_AL}, 156 | {"bl", LEVEL_BASE::REG_BL}, 157 | {"cl", LEVEL_BASE::REG_CL}, 158 | {"dl", LEVEL_BASE::REG_DL}, 159 | {"dil", LEVEL_BASE::REG_DIL}, 160 | {"sil", LEVEL_BASE::REG_SIL}, 161 | {"", REG_INVALID()} 162 | }; 163 | 164 | INT32 Usage() 165 | { 166 | std::cerr << "In-Memory Fuzzing tool" << std::endl; 167 | cerr << endl << KNOB_BASE::StringKnobSummary() << endl; 168 | return -1; 169 | } 170 | 171 | VOID displayCurrentContext(CONTEXT *ctx, UINT32 flag) 172 | { 173 | std::cout << "[" << (flag == CONTEXT_FLG ? "CONTEXT" : "SIGSGV") 174 | << "]=----------------------------------------------------------" << std::endl; 175 | std::cout << std::hex << std::internal << std::setfill('0') 176 | << "RAX = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RAX) << " " 177 | << "RBX = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RBX) << " " 178 | << "RCX = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RCX) << std::endl 179 | << "RDX = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RDX) << " " 180 | << "RDI = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RDI) << " " 181 | << "RSI = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RSI) << std::endl 182 | << "RBP = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RBP) << " " 183 | << "RSP = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RSP) << " " 184 | << "RIP = " << std::setw(16) << PIN_GetContextReg(ctx, LEVEL_BASE::REG_RIP) << std::endl; 185 | std::cout << "+-------------------------------------------------------------------" << std::endl; 186 | } 187 | 188 | static UINT32 fuzzValue; 189 | 190 | VOID randomizeREG(CONTEXT *ctx, ADDRINT nextInsAddr) 191 | { 192 | UINT32 i; 193 | 194 | if (KnobFuzzType.Value() == "random"){ 195 | sleep(1); 196 | srand(time(NULL)); 197 | fuzzValue = (rand() % (KnobMaxValue.Value() - KnobStartValue.Value())) + KnobStartValue.Value(); 198 | } 199 | else if (KnobFuzzType.Value() == "inc"){ 200 | fuzzValue++; 201 | } 202 | 203 | for (i = 0; !(regsRef[i].name.empty()); i++){ 204 | if (regsRef[i].name == KnobREG.Value()){ 205 | PIN_SetContextReg(ctx, regsRef[i].ref, fuzzValue); 206 | break; 207 | } 208 | } 209 | 210 | PIN_SetContextReg(ctx, LEVEL_BASE::REG_RIP, nextInsAddr); 211 | } 212 | 213 | VOID restoreMemory(void) 214 | { 215 | list::iterator i; 216 | 217 | for(i = memInput.begin(); i != memInput.end(); ++i){ 218 | *(reinterpret_cast(i->address)) = i->value; 219 | } 220 | memInput.clear(); 221 | } 222 | 223 | VOID insCallBack(ADDRINT insAddr, std::string insDis, CONTEXT *ctx, ADDRINT nextInsAddr) 224 | { 225 | if (nextInsAddr == KnobStart.Value()){ 226 | if (fuzzValue >= KnobMaxValue.Value()){ 227 | std::cout << "[In-Memory fuzzing stoped. The program continue with the original context]" << std::endl; 228 | displayCurrentContext(ctx, CONTEXT_FLG); 229 | return PIN_RemoveInstrumentation(); 230 | } 231 | std::cout << "[Save Context]" << std::endl; 232 | PIN_SaveContext(ctx, &snapshot); 233 | randomizeREG(ctx, nextInsAddr); 234 | displayCurrentContext(ctx, CONTEXT_FLG); 235 | _lock = UNLOCKED; 236 | PIN_ExecuteAt(ctx); 237 | } 238 | 239 | if (_lock == LOCKED) 240 | return; 241 | 242 | std::cout << "+--> " << std::hex << insAddr << ": " << insDis << std::endl; 243 | 244 | if (insAddr == KnobEnd.Value()){ 245 | _lock = LOCKED; 246 | std::cout << "[Restore Context]" << std::endl; 247 | PIN_SaveContext(&snapshot, ctx); 248 | restoreMemory(); 249 | PIN_ExecuteAt(ctx); 250 | } 251 | } 252 | 253 | VOID WriteMem(ADDRINT insAddr, std::string insDis, ADDRINT memOp) 254 | { 255 | struct memoryInput elem; 256 | ADDRINT addr = memOp; 257 | 258 | if (_lock == LOCKED) 259 | return; 260 | 261 | elem.address = addr; 262 | elem.value = *(reinterpret_cast(addr)); 263 | memInput.push_back(elem); 264 | } 265 | 266 | VOID Instruction(INS ins, VOID *v) 267 | { 268 | PIN_LockClient(); 269 | IMG img = IMG_FindByAddress(INS_Address(ins)); 270 | PIN_UnlockClient(); 271 | 272 | if (IMG_Valid(img) && IMG_IsMainExecutable(img)){ 273 | INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)insCallBack, 274 | IARG_ADDRINT, INS_Address(ins), 275 | IARG_PTR, new string(INS_Disassemble(ins)), 276 | IARG_CONTEXT, 277 | IARG_ADDRINT, INS_NextAddress(ins), 278 | IARG_END); 279 | } 280 | 281 | if (INS_MemoryOperandIsWritten(ins, 0)){ 282 | INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 283 | IARG_ADDRINT, INS_Address(ins), 284 | IARG_PTR, new string(INS_Disassemble(ins)), 285 | IARG_MEMORYOP_EA, 0, 286 | IARG_END); 287 | } 288 | } 289 | 290 | BOOL catchSignal(THREADID tid, INT32 sig, CONTEXT *ctx, BOOL hasHandler, const EXCEPTION_INFO *pExceptInfo, VOID *v) 291 | { 292 | std::cout << std::endl << std::endl << "/!\\ SIGSEGV received /!\\" << std::endl; 293 | displayCurrentContext(ctx, SIGSEGV_FLG); 294 | return true; 295 | } 296 | 297 | int main(int argc, char *argv[]) 298 | { 299 | if(PIN_Init(argc, argv)){ 300 | return Usage(); 301 | } 302 | 303 | if (!KnobStart.Value() || !KnobEnd.Value() || !KnobREG.Value().empty()) 304 | return Usage(); 305 | 306 | if (KnobStartValue.Value() > KnobMaxValue.Value()) 307 | return Usage(); 308 | 309 | fuzzValue = KnobStartValue.Value() - 1; 310 | 311 | PIN_SetSyntaxIntel(); 312 | PIN_InterceptSignal(SIGSEGV, catchSignal, 0); 313 | INS_AddInstrumentFunction(Instruction, 0); 314 | PIN_StartProgram(); 315 | 316 | return 0; 317 | } 318 | 319 | -------------------------------------------------------------------------------- /Taint_analysis_and_pattern_matching_with_Pin/Example-5-Classical-Use-after-free-pattern-matching.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Jonathan Salwan - Copyright (C) 2013-08 3 | // 4 | // http://shell-storm.org 5 | // http://twitter.com/JonathanSalwan 6 | // 7 | // Note: Example 5 - http://shell-storm.org/blog/Taint-analysis-with-Pin/ 8 | // Detect the classical use after free vulnerability 9 | // 10 | 11 | #include "pin.H" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define LOCKED 1 18 | #define UNLOCKED !LOCKED 19 | 20 | #define ALLOCATE 1 21 | #define FREE !ALLOCATE 22 | 23 | static size_t lastSize; 24 | 25 | struct mallocArea 26 | { 27 | UINT64 base; 28 | UINT64 size; 29 | BOOL status; 30 | }; 31 | 32 | UINT32 lockTaint = LOCKED; 33 | 34 | std::list addressTainted; 35 | std::list regsTainted; 36 | std::list mallocAreaList; 37 | 38 | INT32 Usage() 39 | { 40 | std::cerr << "Ex 5" << std::endl; 41 | return -1; 42 | } 43 | 44 | BOOL checkAlreadyRegTainted(REG reg) 45 | { 46 | list::iterator i; 47 | 48 | for(i = regsTainted.begin(); i != regsTainted.end(); i++){ 49 | if (*i == reg){ 50 | return true; 51 | } 52 | } 53 | return false; 54 | } 55 | 56 | VOID removeMemTainted(UINT64 addr) 57 | { 58 | addressTainted.remove(addr); 59 | std::cout << std::hex << "\t\t\t" << addr << " is now freed" << std::endl; 60 | } 61 | 62 | VOID addMemTainted(UINT64 addr) 63 | { 64 | addressTainted.push_back(addr); 65 | std::cout << std::hex << "\t\t\t" << addr << " is now tainted" << std::endl; 66 | } 67 | 68 | BOOL taintReg(REG reg) 69 | { 70 | if (checkAlreadyRegTainted(reg) == true){ 71 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; 72 | return false; 73 | } 74 | 75 | switch(reg){ 76 | 77 | case REG_RAX: regsTainted.push_front(REG_RAX); 78 | case REG_EAX: regsTainted.push_front(REG_EAX); 79 | case REG_AX: regsTainted.push_front(REG_AX); 80 | case REG_AH: regsTainted.push_front(REG_AH); 81 | case REG_AL: regsTainted.push_front(REG_AL); 82 | break; 83 | 84 | case REG_RBX: regsTainted.push_front(REG_RBX); 85 | case REG_EBX: regsTainted.push_front(REG_EBX); 86 | case REG_BX: regsTainted.push_front(REG_BX); 87 | case REG_BH: regsTainted.push_front(REG_BH); 88 | case REG_BL: regsTainted.push_front(REG_BL); 89 | break; 90 | 91 | case REG_RCX: regsTainted.push_front(REG_RCX); 92 | case REG_ECX: regsTainted.push_front(REG_ECX); 93 | case REG_CX: regsTainted.push_front(REG_CX); 94 | case REG_CH: regsTainted.push_front(REG_CH); 95 | case REG_CL: regsTainted.push_front(REG_CL); 96 | break; 97 | 98 | case REG_RDX: regsTainted.push_front(REG_RDX); 99 | case REG_EDX: regsTainted.push_front(REG_EDX); 100 | case REG_DX: regsTainted.push_front(REG_DX); 101 | case REG_DH: regsTainted.push_front(REG_DH); 102 | case REG_DL: regsTainted.push_front(REG_DL); 103 | break; 104 | 105 | case REG_RDI: regsTainted.push_front(REG_RDI); 106 | case REG_EDI: regsTainted.push_front(REG_EDI); 107 | case REG_DI: regsTainted.push_front(REG_DI); 108 | case REG_DIL: regsTainted.push_front(REG_DIL); 109 | break; 110 | 111 | case REG_RSI: regsTainted.push_front(REG_RSI); 112 | case REG_ESI: regsTainted.push_front(REG_ESI); 113 | case REG_SI: regsTainted.push_front(REG_SI); 114 | case REG_SIL: regsTainted.push_front(REG_SIL); 115 | break; 116 | 117 | default: 118 | std::cout << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; 119 | return false; 120 | } 121 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; 122 | return true; 123 | } 124 | 125 | BOOL removeRegTainted(REG reg) 126 | { 127 | switch(reg){ 128 | 129 | case REG_RAX: regsTainted.remove(REG_RAX); 130 | case REG_EAX: regsTainted.remove(REG_EAX); 131 | case REG_AX: regsTainted.remove(REG_AX); 132 | case REG_AH: regsTainted.remove(REG_AH); 133 | case REG_AL: regsTainted.remove(REG_AL); 134 | break; 135 | 136 | case REG_RBX: regsTainted.remove(REG_RBX); 137 | case REG_EBX: regsTainted.remove(REG_EBX); 138 | case REG_BX: regsTainted.remove(REG_BX); 139 | case REG_BH: regsTainted.remove(REG_BH); 140 | case REG_BL: regsTainted.remove(REG_BL); 141 | break; 142 | 143 | case REG_RCX: regsTainted.remove(REG_RCX); 144 | case REG_ECX: regsTainted.remove(REG_ECX); 145 | case REG_CX: regsTainted.remove(REG_CX); 146 | case REG_CH: regsTainted.remove(REG_CH); 147 | case REG_CL: regsTainted.remove(REG_CL); 148 | break; 149 | 150 | case REG_RDX: regsTainted.remove(REG_RDX); 151 | case REG_EDX: regsTainted.remove(REG_EDX); 152 | case REG_DX: regsTainted.remove(REG_DX); 153 | case REG_DH: regsTainted.remove(REG_DH); 154 | case REG_DL: regsTainted.remove(REG_DL); 155 | break; 156 | 157 | case REG_RDI: regsTainted.remove(REG_RDI); 158 | case REG_EDI: regsTainted.remove(REG_EDI); 159 | case REG_DI: regsTainted.remove(REG_DI); 160 | case REG_DIL: regsTainted.remove(REG_DIL); 161 | break; 162 | 163 | case REG_RSI: regsTainted.remove(REG_RSI); 164 | case REG_ESI: regsTainted.remove(REG_ESI); 165 | case REG_SI: regsTainted.remove(REG_SI); 166 | case REG_SIL: regsTainted.remove(REG_SIL); 167 | break; 168 | 169 | default: 170 | return false; 171 | } 172 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; 173 | return true; 174 | } 175 | 176 | VOID ReadMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp, UINT64 sp) 177 | { 178 | list::iterator i; 179 | list::iterator i2; 180 | UINT64 addr = memOp; 181 | 182 | if (opCount != 2) 183 | return; 184 | 185 | for(i2 = mallocAreaList.begin(); i2 != mallocAreaList.end(); i2++){ 186 | if (addr >= i2->base && addr < (i2->base + i2->size) && i2->status == FREE){ 187 | std::cout << std::hex << "[UAF in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 188 | return; 189 | } 190 | } 191 | 192 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 193 | if (addr == *i){ 194 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 195 | taintReg(reg_r); 196 | 197 | if (sp > addr && addr > 0x700000000000) 198 | std::cout << std::hex << "[UAF in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 199 | 200 | return; 201 | } 202 | } 203 | if (checkAlreadyRegTainted(reg_r)){ 204 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 205 | removeRegTainted(reg_r); 206 | } 207 | } 208 | 209 | VOID WriteMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp, UINT64 sp) 210 | { 211 | list::iterator i; 212 | list::iterator i2; 213 | UINT64 addr = memOp; 214 | 215 | if (opCount != 2) 216 | return; 217 | 218 | for(i2 = mallocAreaList.begin(); i2 != mallocAreaList.end(); i2++){ 219 | if (addr >= i2->base && addr < (i2->base + i2->size) && i2->status == FREE){ 220 | std::cout << std::hex << "[UAF in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 221 | return; 222 | } 223 | } 224 | 225 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 226 | if (addr == *i){ 227 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 228 | if (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r)) 229 | removeMemTainted(addr); 230 | 231 | if (sp > addr && addr > 0x700000000000) 232 | std::cout << std::hex << "[UAF in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 233 | 234 | return ; 235 | } 236 | } 237 | if (checkAlreadyRegTainted(reg_r)){ 238 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 239 | addMemTainted(addr); 240 | } 241 | } 242 | 243 | VOID spreadRegTaint(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, REG reg_w) 244 | { 245 | if (opCount != 2) 246 | return; 247 | 248 | if (REG_valid(reg_w)){ 249 | if (checkAlreadyRegTainted(reg_w) && (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r))){ 250 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 251 | std::cout << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; 252 | removeRegTainted(reg_w); 253 | } 254 | else if (!checkAlreadyRegTainted(reg_w) && checkAlreadyRegTainted(reg_r)){ 255 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 256 | std::cout << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; 257 | taintReg(reg_w); 258 | } 259 | } 260 | } 261 | 262 | VOID followData(UINT64 insAddr, std::string insDis, REG reg) 263 | { 264 | if (!REG_valid(reg)) 265 | return; 266 | 267 | if (checkAlreadyRegTainted(reg)){ 268 | std::cout << "[FOLLOW]\t\t" << insAddr << ": " << insDis << std::endl; 269 | } 270 | } 271 | 272 | VOID Instruction(INS ins, VOID *v) 273 | { 274 | if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 275 | INS_InsertCall( 276 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 277 | IARG_ADDRINT, INS_Address(ins), 278 | IARG_PTR, new string(INS_Disassemble(ins)), 279 | IARG_UINT32, INS_OperandCount(ins), 280 | IARG_UINT32, INS_OperandReg(ins, 0), 281 | IARG_MEMORYOP_EA, 0, 282 | IARG_REG_VALUE, REG_STACK_PTR, 283 | IARG_END); 284 | } 285 | else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ 286 | INS_InsertCall( 287 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 288 | IARG_ADDRINT, INS_Address(ins), 289 | IARG_PTR, new string(INS_Disassemble(ins)), 290 | IARG_UINT32, INS_OperandCount(ins), 291 | IARG_UINT32, INS_OperandReg(ins, 1), 292 | IARG_MEMORYOP_EA, 0, 293 | IARG_REG_VALUE, REG_STACK_PTR, 294 | IARG_END); 295 | } 296 | else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 297 | INS_InsertCall( 298 | ins, IPOINT_BEFORE, (AFUNPTR)spreadRegTaint, 299 | IARG_ADDRINT, INS_Address(ins), 300 | IARG_PTR, new string(INS_Disassemble(ins)), 301 | IARG_UINT32, INS_OperandCount(ins), 302 | IARG_UINT32, INS_RegR(ins, 0), 303 | IARG_UINT32, INS_RegW(ins, 0), 304 | IARG_END); 305 | } 306 | 307 | if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 308 | INS_InsertCall( 309 | ins, IPOINT_BEFORE, (AFUNPTR)followData, 310 | IARG_ADDRINT, INS_Address(ins), 311 | IARG_PTR, new string(INS_Disassemble(ins)), 312 | IARG_UINT32, INS_RegR(ins, 0), 313 | IARG_END); 314 | } 315 | } 316 | 317 | VOID callbackBeforeMalloc(ADDRINT size) 318 | { 319 | lastSize = size; 320 | } 321 | 322 | VOID callbackBeforeFree(ADDRINT addr) 323 | { 324 | list::iterator i; 325 | 326 | std::cout << "[INFO]\t\tfree(" << std::hex << addr << ")" << std::endl; 327 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 328 | if (addr == i->base){ 329 | i->status = FREE; 330 | break; 331 | } 332 | } 333 | } 334 | 335 | VOID callbackAfterMalloc(ADDRINT ret) 336 | { 337 | list::iterator i; 338 | struct mallocArea elem; 339 | 340 | std::cout << "[INFO]\t\tmalloc(" << lastSize << ") = " << std::hex << ret << std::endl; 341 | if (ret){ 342 | 343 | for(i = mallocAreaList.begin(); i != mallocAreaList.end(); i++){ 344 | if (ret == i->base){ 345 | i->status = ALLOCATE; 346 | i->size = lastSize; 347 | return; 348 | } 349 | } 350 | elem.base = ret; 351 | elem.size = lastSize; 352 | elem.status = ALLOCATE; 353 | mallocAreaList.push_front(elem); 354 | } 355 | } 356 | 357 | VOID Image(IMG img, VOID *v) 358 | { 359 | RTN mallocRtn = RTN_FindByName(img, "malloc"); 360 | RTN freeRtn = RTN_FindByName(img, "free"); 361 | 362 | if (RTN_Valid(mallocRtn)){ 363 | RTN_Open(mallocRtn); 364 | 365 | RTN_InsertCall( 366 | mallocRtn, 367 | IPOINT_BEFORE, (AFUNPTR)callbackBeforeMalloc, 368 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, 369 | IARG_END); 370 | 371 | RTN_InsertCall( 372 | mallocRtn, 373 | IPOINT_AFTER, (AFUNPTR)callbackAfterMalloc, 374 | IARG_FUNCRET_EXITPOINT_VALUE, 375 | IARG_END); 376 | 377 | RTN_Close(mallocRtn); 378 | } 379 | 380 | if (RTN_Valid(freeRtn)){ 381 | RTN_Open(freeRtn); 382 | RTN_InsertCall( 383 | freeRtn, 384 | IPOINT_BEFORE, (AFUNPTR)callbackBeforeFree, 385 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, 386 | IARG_END); 387 | RTN_Close(freeRtn); 388 | } 389 | } 390 | 391 | int main(int argc, char *argv[]) 392 | { 393 | PIN_InitSymbols(); 394 | if(PIN_Init(argc, argv)){ 395 | return Usage(); 396 | } 397 | 398 | PIN_SetSyntaxIntel(); 399 | IMG_AddInstrumentFunction(Image, 0); 400 | INS_AddInstrumentFunction(Instruction, 0); 401 | PIN_StartProgram(); 402 | 403 | return 0; 404 | } 405 | 406 | -------------------------------------------------------------------------------- /NDH_2013_CTF_unpack_kernel_3.7.10.patch: -------------------------------------------------------------------------------- 1 | diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c 2 | index fbd9f60..108f1f8 100644 3 | --- a/fs/binfmt_elf.c 4 | +++ b/fs/binfmt_elf.c 5 | @@ -69,6 +69,10 @@ static int elf_core_dump(struct coredump_params *cprm); 6 | #define ELF_CORE_EFLAGS 0 7 | #endif 8 | 9 | +#ifdef CONFIG_NDH 10 | +#define PACKED_MASK 0x20 11 | +#endif 12 | + 13 | #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1)) 14 | #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1)) 15 | #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1)) 16 | @@ -216,7 +220,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, 17 | } while (0) 18 | 19 | #ifdef ARCH_DLINFO 20 | - /* 21 | + /* 22 | * ARCH_DLINFO must come first so PPC can do its special alignment of 23 | * AUXV. 24 | * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT() in 25 | @@ -424,7 +428,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, 26 | error = -EIO; 27 | if (retval != size) { 28 | if (retval < 0) 29 | - error = retval; 30 | + error = retval; 31 | goto out_close; 32 | } 33 | 34 | @@ -558,6 +562,34 @@ static unsigned long randomize_stack_top(unsigned long stack_top) 35 | #endif 36 | } 37 | 38 | +#ifdef CONFIG_NDH 39 | +static int upk_binary(long unsigned int start_code, unsigned long e_entry, 40 | + unsigned long p_filesz) 41 | +{ 42 | + unsigned long base, size, x, i; 43 | + unsigned char *p; 44 | + 45 | + unsigned char key[] = { 46 | + 0x12, 0x43, 0x34, 0x65, 0x78, 0xcf, 0xdc, 47 | + 0xca, 0x98, 0x90, 0x65, 0x31, 0x21, 0x56, 48 | + 0x83, 0xfa, 0xcd, 0x30, 0xfd, 0x12, 0x84, 49 | + 0x98, 0xb7, 0x54, 0xa5, 0x62, 0x61, 0xf9, 50 | + 0xe3, 0x09, 0xc8, 0x94, 0x12, 0xe6, 0x87 51 | + }; 52 | + 53 | + base = e_entry - start_code; /* base physique */ 54 | + size = p_filesz - base; 55 | + 56 | + p = (unsigned char *)e_entry; 57 | + for (i = 0, x = 0 ; i < size ; i++, x++){ 58 | + if (x == 35) 59 | + x = 0; 60 | + p[i] ^= key[x]; 61 | + } 62 | + return 0; 63 | +} 64 | +#endif 65 | + 66 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 67 | { 68 | struct file *interpreter = NULL; /* to shut gcc up */ 69 | @@ -570,6 +602,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 70 | int retval, i; 71 | unsigned int size; 72 | unsigned long elf_entry; 73 | +#ifdef CONFIG_NDH 74 | + unsigned long packer_flag = 0; 75 | +#endif 76 | unsigned long interp_load_addr = 0; 77 | unsigned long start_code, end_code, start_data, end_data; 78 | unsigned long reloc_func_desc __maybe_unused = 0; 79 | @@ -585,10 +620,16 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 80 | retval = -ENOMEM; 81 | goto out_ret; 82 | } 83 | - 84 | + 85 | /* Get the exec-header */ 86 | loc->elf_ex = *((struct elfhdr *)bprm->buf); 87 | 88 | +#ifdef CONFIG_NDH 89 | + if (loc->elf_ex.e_flags & PACKED_MASK){ 90 | + packer_flag = 1; 91 | + } 92 | +#endif 93 | + 94 | retval = -ENOEXEC; 95 | /* First of all, some simple consistency checks */ 96 | if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) 97 | @@ -637,7 +678,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 98 | * is an a.out format binary 99 | */ 100 | retval = -ENOEXEC; 101 | - if (elf_ppnt->p_filesz > PATH_MAX || 102 | + if (elf_ppnt->p_filesz > PATH_MAX || 103 | elf_ppnt->p_filesz < 2) 104 | goto out_free_ph; 105 | 106 | @@ -737,7 +778,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 107 | send_sig(SIGKILL, current, 0); 108 | goto out_free_dentry; 109 | } 110 | - 111 | + 112 | current->mm->start_stack = bprm->p; 113 | 114 | /* Now we do a little grungy work by mmapping the ELF image into 115 | @@ -752,7 +793,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 116 | 117 | if (unlikely (elf_brk > elf_bss)) { 118 | unsigned long nbyte; 119 | - 120 | + 121 | /* There was a PT_LOAD segment with p_memsz > p_filesz 122 | before this one. Map anonymous pages, if needed, 123 | and clear the area. */ 124 | @@ -948,6 +989,18 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) 125 | current->mm->end_data = end_data; 126 | current->mm->start_stack = bprm->p; 127 | 128 | +#ifdef CONFIG_NDH 129 | + elf_ppnt = elf_phdata; 130 | + for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++){ 131 | + if (elf_ppnt->p_type == PT_LOAD){ 132 | + if (packer_flag && (elf_ppnt->p_flags & 0x2)) 133 | + upk_binary(start_code, loc->elf_ex.e_entry, 134 | + elf_ppnt->p_filesz); 135 | + break; 136 | + } 137 | + } 138 | +#endif 139 | + 140 | #ifdef arch_randomize_brk 141 | if ((current->flags & PF_RANDOMIZE) && (randomize_va_space > 1)) { 142 | current->mm->brk = current->mm->start_brk = 143 | @@ -1282,7 +1335,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, loff_t offset) 144 | return; 145 | } 146 | 147 | -static void fill_note(struct memelfnote *note, const char *name, int type, 148 | +static void fill_note(struct memelfnote *note, const char *name, int type, 149 | unsigned int sz, void *data) 150 | { 151 | note->name = name; 152 | @@ -1331,7 +1384,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, 153 | { 154 | const struct cred *cred; 155 | unsigned int i, len; 156 | - 157 | + 158 | /* first copy the parameters from user space */ 159 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); 160 | 161 | @@ -1365,7 +1418,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, 162 | SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid)); 163 | rcu_read_unlock(); 164 | strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); 165 | - 166 | + 167 | return 0; 168 | } 169 | 170 | @@ -1764,8 +1817,8 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) 171 | t->num_notes = 0; 172 | 173 | fill_prstatus(&t->prstatus, p, signr); 174 | - elf_core_copy_task_regs(p, &t->prstatus.pr_reg); 175 | - 176 | + elf_core_copy_task_regs(p, &t->prstatus.pr_reg); 177 | + 178 | fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), 179 | &(t->prstatus)); 180 | t->num_notes++; 181 | @@ -1786,7 +1839,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t) 182 | t->num_notes++; 183 | sz += notesize(&t->notes[2]); 184 | } 185 | -#endif 186 | +#endif 187 | return sz; 188 | } 189 | 190 | @@ -2038,7 +2091,7 @@ static int elf_core_dump(struct coredump_params *cprm) 191 | 192 | /* 193 | * We no longer stop all VM operations. 194 | - * 195 | + * 196 | * This is because those proceses that could possibly change map_count 197 | * or the mmap / vma pages are now blocked in do_exit on current 198 | * finishing this core dump. 199 | @@ -2047,7 +2100,7 @@ static int elf_core_dump(struct coredump_params *cprm) 200 | * the map_count or the pages allocated. So no possibility of crashing 201 | * exists while dumping the mm->vm_next areas to the core file. 202 | */ 203 | - 204 | + 205 | /* alloc memory for large data structures: too large to be on stack */ 206 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); 207 | if (!elf) 208 | @@ -2080,7 +2133,7 @@ static int elf_core_dump(struct coredump_params *cprm) 209 | 210 | has_dumped = 1; 211 | current->flags |= PF_DUMPCORE; 212 | - 213 | + 214 | fs = get_fs(); 215 | set_fs(KERNEL_DS); 216 | 217 | diff --git a/fs/coredump.c b/fs/coredump.c 218 | index ce47379..245d5af 100644 219 | --- a/fs/coredump.c 220 | +++ b/fs/coredump.c 221 | @@ -460,6 +460,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) 222 | 223 | void do_coredump(siginfo_t *siginfo, struct pt_regs *regs) 224 | { 225 | +#ifndef CONFIG_NDH 226 | struct core_state core_state; 227 | struct core_name cn; 228 | struct mm_struct *mm = current->mm; 229 | @@ -483,7 +484,13 @@ void do_coredump(siginfo_t *siginfo, struct pt_regs *regs) 230 | */ 231 | .mm_flags = mm->flags, 232 | }; 233 | +#endif 234 | 235 | +#ifdef CONFIG_NDH 236 | + goto fail; 237 | +#endif 238 | + 239 | +#ifndef CONFIG_NDH 240 | audit_core_dumps(siginfo->si_signo); 241 | 242 | binfmt = mm->binfmt; 243 | @@ -648,6 +655,7 @@ fail_corename: 244 | revert_creds(old_cred); 245 | fail_creds: 246 | put_cred(cred); 247 | +#endif 248 | fail: 249 | return; 250 | } 251 | diff --git a/fs/proc/base.c b/fs/proc/base.c 252 | index 9e28356..d42f081 100644 253 | --- a/fs/proc/base.c 254 | +++ b/fs/proc/base.c 255 | @@ -209,10 +209,10 @@ static int proc_pid_cmdline(struct task_struct *task, char * buffer) 256 | goto out_mm; /* Shh! No looking before we're done */ 257 | 258 | len = mm->arg_end - mm->arg_start; 259 | - 260 | + 261 | if (len > PAGE_SIZE) 262 | len = PAGE_SIZE; 263 | - 264 | + 265 | res = access_process_vm(task, mm->arg_start, buffer, len, 0); 266 | 267 | // If the nul at the end of args has been overwritten, then 268 | @@ -2051,7 +2051,7 @@ out: 269 | return error; 270 | } 271 | 272 | -static struct dentry *proc_pident_lookup(struct inode *dir, 273 | +static struct dentry *proc_pident_lookup(struct inode *dir, 274 | struct dentry *dentry, 275 | const struct pid_entry *ents, 276 | unsigned int nents) 277 | @@ -2672,7 +2672,9 @@ static const struct pid_entry tgid_base_stuff[] = { 278 | #ifdef CONFIG_NUMA 279 | REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations), 280 | #endif 281 | +#ifndef CONFIG_NDH 282 | REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), 283 | +#endif 284 | LNK("cwd", proc_cwd_link), 285 | LNK("root", proc_root_link), 286 | LNK("exe", proc_exe_link), 287 | diff --git a/kernel/ptrace.c b/kernel/ptrace.c 288 | index fbea91d..0150798 100644 289 | --- a/kernel/ptrace.c 290 | +++ b/kernel/ptrace.c 291 | @@ -25,12 +25,13 @@ 292 | #include 293 | #include 294 | 295 | - 296 | +#ifndef CONFIG_NDH 297 | static int ptrace_trapping_sleep_fn(void *flags) 298 | { 299 | schedule(); 300 | return 0; 301 | } 302 | +#endif 303 | 304 | /* 305 | * ptrace a task: make the debugger its new parent and 306 | @@ -141,6 +142,7 @@ static bool ptrace_freeze_traced(struct task_struct *task) 307 | return ret; 308 | } 309 | 310 | +#ifndef CONFIG_NDH 311 | static void ptrace_unfreeze_traced(struct task_struct *task) 312 | { 313 | if (task->state != __TASK_TRACED) 314 | @@ -155,6 +157,7 @@ static void ptrace_unfreeze_traced(struct task_struct *task) 315 | task->state = TASK_TRACED; 316 | spin_unlock_irq(&task->sighand->siglock); 317 | } 318 | +#endif 319 | 320 | /** 321 | * ptrace_check_attach - check whether ptracee is ready for ptrace operation 322 | @@ -269,6 +272,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode) 323 | return !err; 324 | } 325 | 326 | +#ifndef CONFIG_NDH 327 | static int ptrace_attach(struct task_struct *task, long request, 328 | unsigned long addr, 329 | unsigned long flags) 330 | @@ -368,6 +372,7 @@ out: 331 | 332 | return retval; 333 | } 334 | +#endif 335 | 336 | /** 337 | * ptrace_traceme -- helper for PTRACE_TRACEME 338 | @@ -375,6 +380,7 @@ out: 339 | * Performs checks and sets PT_PTRACED. 340 | * Should be used by all ptrace implementations for PTRACE_TRACEME. 341 | */ 342 | +#ifndef CONFIG_NDH 343 | static int ptrace_traceme(void) 344 | { 345 | int ret = -EPERM; 346 | @@ -397,6 +403,7 @@ static int ptrace_traceme(void) 347 | 348 | return ret; 349 | } 350 | +#endif 351 | 352 | /* 353 | * Called with irqs disabled, returns true if childs should reap themselves. 354 | @@ -875,6 +882,7 @@ int ptrace_request(struct task_struct *child, long request, 355 | return ret; 356 | } 357 | 358 | +#ifndef CONFIG_NDH 359 | static struct task_struct *ptrace_get_task_struct(pid_t pid) 360 | { 361 | struct task_struct *child; 362 | @@ -889,6 +897,7 @@ static struct task_struct *ptrace_get_task_struct(pid_t pid) 363 | return ERR_PTR(-ESRCH); 364 | return child; 365 | } 366 | +#endif 367 | 368 | #ifndef arch_ptrace_attach 369 | #define arch_ptrace_attach(child) do { } while (0) 370 | @@ -897,9 +906,16 @@ static struct task_struct *ptrace_get_task_struct(pid_t pid) 371 | SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, 372 | unsigned long, data) 373 | { 374 | +#ifndef CONFIG_NDH 375 | struct task_struct *child; 376 | +#endif 377 | long ret; 378 | +#ifdef CONFIG_NDH 379 | + ret = EFAULT; 380 | + goto out; 381 | +#endif 382 | 383 | +#ifndef CONFIG_NDH 384 | if (request == PTRACE_TRACEME) { 385 | ret = ptrace_traceme(); 386 | if (!ret) 387 | @@ -935,6 +951,7 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, 388 | 389 | out_put_task_struct: 390 | put_task_struct(child); 391 | +#endif 392 | out: 393 | return ret; 394 | } 395 | @@ -1044,9 +1061,12 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, 396 | asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, 397 | compat_long_t addr, compat_long_t data) 398 | { 399 | +#ifndef CONFIG_NDH 400 | struct task_struct *child; 401 | - long ret; 402 | +#endif 403 | + long ret = -EFAULT; 404 | 405 | +#ifndef CONFIG_NDH 406 | if (request == PTRACE_TRACEME) { 407 | ret = ptrace_traceme(); 408 | goto out; 409 | @@ -1080,6 +1100,7 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, 410 | out_put_task_struct: 411 | put_task_struct(child); 412 | out: 413 | +#endif 414 | return ret; 415 | } 416 | #endif /* CONFIG_COMPAT */ 417 | diff --git a/security/keys/Kconfig b/security/keys/Kconfig 418 | index a90d6d3..cf4cfc9 100644 419 | --- a/security/keys/Kconfig 420 | +++ b/security/keys/Kconfig 421 | @@ -2,6 +2,12 @@ 422 | # Key management configuration 423 | # 424 | 425 | +config NDH 426 | + bool "Kernel modification to CTF NDH 2013" 427 | + default n 428 | + help 429 | + Kernel modification to CTF NDH 2013 430 | + 431 | config KEYS 432 | bool "Enable access key retention support" 433 | help 434 | -------------------------------------------------------------------------------- /k1986.c: -------------------------------------------------------------------------------- 1 | /* 2 | ** Jonathan Salwan - Copyright (C) 2013-26 3 | ** 4 | ** http://twitter.com/JonathanSalwan 5 | ** http://shell-storm.org 6 | ** 7 | ** This program is free software: you can redistribute it and/or modify 8 | ** it under the terms of the GNU General Public License as published by 9 | ** the Free Software Foundation, either version 3 of the License, or 10 | ** (at your option) any later version. 11 | ** 12 | ** ndh2k13 ctf challenge - The k1986's source code 13 | ** 14 | ** $ gcc -W -Wall -Wextra -ansi -pedantic -D_BSD_SOURCE -D_POSIX_SOURCE \ 15 | ** -lpthread -std=c99 -o k1986 ./k1986.c 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define SERV_PORT 1024 34 | #define MAX_CLIENT 256 35 | #define MAX_CLIENT_QUEUE 32 36 | 37 | #define TRUE 0 38 | #define FALSE !TRUE 39 | #define SUCCESS 0 40 | #define ERROR !SUCCESS 41 | 42 | #define RC4_KEY "\x90\x3f\x8e\x7f\x8a" 43 | 44 | #define __PRIVATE__ 45 | #define __API__ 46 | 47 | #define CALL_PTR(func) \ 48 | __asm__("lea 0x0a(%rip), %rax"); \ 49 | __asm__("push %rax"); \ 50 | __asm__("push %0" :: "l"(func)); \ 51 | __asm__("ret"); \ 52 | 53 | #define CALL_FUNC(func) \ 54 | __asm__("lea 0x08(%rip), %rax"); \ 55 | __asm__("push %rax"); \ 56 | __asm__("push %0" :: "l"(func)); \ 57 | __asm__("ret"); \ 58 | 59 | #define CALL_ARG_CONST(func, arg1) \ 60 | __asm__("lea 0x0f(%rip), %rax"); \ 61 | __asm__("push %rax"); \ 62 | __asm__("mov %0, %%rdi" :: "i"(arg1)); \ 63 | __asm__("push %0" :: "l"(func)); \ 64 | __asm__("ret"); 65 | 66 | #define BB_BREAK1() \ 67 | __asm__("push %rax"); \ 68 | __asm__("lea 0x02(%rip), %rax"); \ 69 | __asm__("push %rax"); \ 70 | __asm__("ret"); \ 71 | __asm__("pop %rax"); 72 | 73 | #define JUNK1() \ 74 | __asm__("jmp 2f"); \ 75 | __asm__("1:"); \ 76 | __asm__("push %rsi"); \ 77 | __asm__("mov %rax, %rsi"); \ 78 | __asm__("push %rax"); \ 79 | __asm__("xor $0x61, %rsi"); \ 80 | __asm__("shr $0x3, %rax"); \ 81 | __asm__("pop %rsi"); \ 82 | __asm__("pop %rax"); \ 83 | __asm__("jmp 3f"); \ 84 | __asm__("2:"); \ 85 | __asm__("jmp 1b"); \ 86 | __asm__("3:"); 87 | 88 | #define JUNK2() \ 89 | __asm__("push %rdi"); \ 90 | __asm__("push %rbx"); \ 91 | __asm__("xor %rbx, %rdi"); \ 92 | __asm__("shr $0x3, %rbx"); \ 93 | __asm__("pop %rdi"); \ 94 | __asm__("pop %rbx"); 95 | 96 | typedef struct client_s { 97 | unsigned char buff[256]; 98 | int32_t fd; 99 | struct sockaddr_in addr; 100 | struct client_s *next; 101 | struct client_s *prev; 102 | } client_t; 103 | 104 | typedef struct api_s { 105 | void(*addClient)(client_t*); 106 | void(*delClient)(client_t*); 107 | } api_t; 108 | 109 | typedef struct coreServ_s { 110 | /* Attributs */ 111 | int32_t fd; 112 | int32_t on; 113 | client_t *clients; 114 | client_t *fclient; 115 | api_t api; 116 | struct sockaddr_in addr; 117 | struct timeval timeout; 118 | pthread_t threadConHandler; 119 | pthread_t threadMoniClient; 120 | pthread_mutex_t mutex; 121 | fd_set readfs; 122 | /* Methodes */ 123 | void(*initSocket)(void); 124 | void(*startServ)(void); 125 | void*(*waitingClient)(void*); 126 | void*(*monitoringClient)(void*); 127 | } coreServ_t; 128 | 129 | static void __PRIVATE__ initSockServ(void); 130 | static void __PRIVATE__ startServ(void); 131 | static void __PRIVATE__ *servWaitingClient(void*); 132 | static void __PRIVATE__ *monitoringClient(void*); 133 | static void __API__ addClient(client_t *newCli); 134 | static void __API__ delClient(client_t *newCli); 135 | 136 | coreServ_t coreServ = { 137 | .fd = 0, 138 | .clients = NULL, 139 | .initSocket = __PRIVATE__ initSockServ, 140 | .startServ = __PRIVATE__ startServ, 141 | .waitingClient = __PRIVATE__ servWaitingClient, 142 | .monitoringClient = __PRIVATE__ monitoringClient, 143 | .api = { 144 | .delClient = __API__ delClient, 145 | .addClient = __API__ addClient, 146 | }, 147 | .timeout = { 148 | .tv_usec = 0, 149 | .tv_sec = 1, 150 | } 151 | }; 152 | 153 | static void __PRIVATE__ initSockServ(void){ 154 | BB_BREAK1(); 155 | JUNK1(); 156 | if ((coreServ.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 157 | perror("socket"); 158 | CALL_ARG_CONST(exit, -1); 159 | } 160 | JUNK2(); 161 | BB_BREAK1(); 162 | if (setsockopt(coreServ.fd, SOL_SOCKET, SO_REUSEADDR, (char*)&coreServ.on, sizeof(int)) < 0){ 163 | perror("setsockopt"); 164 | close(coreServ.fd); 165 | CALL_ARG_CONST(exit, -1); 166 | } 167 | BB_BREAK1(); 168 | JUNK1(); 169 | memset(&coreServ.addr, 0x00, sizeof(struct sockaddr_in)); 170 | coreServ.addr.sin_family = AF_INET; 171 | coreServ.addr.sin_port = htons(SERV_PORT); 172 | JUNK2(); 173 | coreServ.addr.sin_addr.s_addr = htonl(INADDR_ANY); 174 | } 175 | 176 | static void __API__ addClient(client_t *newCli){ 177 | pthread_mutex_lock(&coreServ.mutex); 178 | JUNK1(); 179 | if (coreServ.clients != NULL){ 180 | BB_BREAK1(); 181 | newCli->next = coreServ.clients->next; 182 | newCli->prev = coreServ.clients; 183 | coreServ.clients->next = newCli; 184 | coreServ.fclient->prev = newCli; 185 | coreServ.clients = newCli; 186 | } 187 | else { 188 | BB_BREAK1(); 189 | newCli->next = newCli; 190 | newCli->prev = newCli; 191 | coreServ.clients = newCli; 192 | coreServ.fclient = newCli; 193 | } 194 | JUNK2(); 195 | pthread_mutex_unlock(&coreServ.mutex); 196 | } 197 | 198 | static void __API__ delClient(client_t *cli){ 199 | if (cli->next == cli && cli->prev == cli){ 200 | BB_BREAK1(); 201 | coreServ.clients = NULL; 202 | coreServ.fclient = NULL; 203 | JUNK2(); 204 | } 205 | else { 206 | BB_BREAK1(); 207 | cli->prev->next = cli->next; 208 | cli->next->prev = cli->prev; 209 | if (cli == coreServ.fclient){ 210 | BB_BREAK1(); 211 | coreServ.fclient = cli->next; 212 | } 213 | if (cli == coreServ.clients){ 214 | BB_BREAK1(); 215 | JUNK1(); 216 | coreServ.clients = cli->next; 217 | } 218 | } 219 | JUNK1(); 220 | printf("Connexion closed: %s\n", inet_ntoa(cli->addr.sin_addr)); 221 | close(cli->fd); 222 | JUNK2(); 223 | free(cli); 224 | } 225 | 226 | static void __PRIVATE__ *servWaitingClient(void *args){ 227 | struct sockaddr_in cliAddr; 228 | int32_t fdCli; 229 | uint32_t sinSize; 230 | client_t *newClient; 231 | 232 | (void)args; 233 | BB_BREAK1(); 234 | sinSize = sizeof(struct sockaddr_in); 235 | if (bind(coreServ.fd, (struct sockaddr *)&coreServ.addr, sizeof(coreServ.addr)) < 0){ 236 | BB_BREAK1(); 237 | perror("bind"); 238 | JUNK2(); 239 | close(coreServ.fd); 240 | CALL_ARG_CONST(exit, -1); 241 | } 242 | if (listen(coreServ.fd, MAX_CLIENT_QUEUE) < 0){ 243 | BB_BREAK1(); 244 | perror("listen"); 245 | JUNK1(); 246 | close(coreServ.fd); 247 | CALL_ARG_CONST(exit, -1); 248 | } 249 | while (1){ 250 | if ((fdCli = accept(coreServ.fd, (struct sockaddr *)&cliAddr, &sinSize)) < 0){ 251 | BB_BREAK1(); 252 | perror("accept"); 253 | JUNK1(); 254 | close(coreServ.fd); 255 | CALL_ARG_CONST(exit, -1); 256 | } 257 | printf("Connexion received: %s\n", inet_ntoa(cliAddr.sin_addr)); 258 | if ((newClient = malloc(sizeof(client_t))) == NULL){ 259 | JUNK1(); 260 | BB_BREAK1(); 261 | perror("malloc"); 262 | JUNK1(); 263 | continue; 264 | } 265 | BB_BREAK1(); 266 | JUNK2(); 267 | newClient->fd = fdCli; 268 | newClient->addr = cliAddr; 269 | JUNK2(); 270 | coreServ.api.addClient(newClient); 271 | } 272 | BB_BREAK1(); 273 | JUNK1(); 274 | /* never go here */ 275 | CALL_ARG_CONST(pthread_exit, 0); 276 | } 277 | 278 | static void __PRIVATE__ fdSetAll(void){ 279 | client_t *ptr; 280 | int stop = 0; 281 | 282 | BB_BREAK1(); 283 | JUNK1(); 284 | pthread_mutex_lock(&coreServ.mutex); 285 | ptr = coreServ.clients; 286 | JUNK1(); 287 | FD_ZERO(&coreServ.readfs); 288 | while (ptr && ptr->fd != stop){ 289 | BB_BREAK1(); 290 | if (stop == 0) 291 | stop = ptr->fd; 292 | FD_SET(ptr->fd, &coreServ.readfs); 293 | ptr = ptr->next; 294 | } 295 | JUNK2(); 296 | pthread_mutex_unlock(&coreServ.mutex); 297 | } 298 | 299 | static void recvData(int ret, client_t *cli); 300 | 301 | static void __PRIVATE__ fdIssetAll(void){ 302 | client_t *ptr; 303 | int stop = 0; 304 | int ret = 0; 305 | 306 | BB_BREAK1(); 307 | JUNK1(); 308 | pthread_mutex_lock(&coreServ.mutex); 309 | ptr = coreServ.clients; 310 | while (ptr && ptr->fd != stop){ 311 | BB_BREAK1(); 312 | if (stop == 0) 313 | stop = ptr->fd; 314 | if (FD_ISSET(ptr->fd, &coreServ.readfs)){ 315 | BB_BREAK1(); 316 | memset(ptr->buff, 0x00, sizeof(ptr->buff)); 317 | JUNK2(); 318 | ret = read(ptr->fd, ptr->buff, sizeof(ptr->buff)-1); 319 | if (ret <= 0){ 320 | BB_BREAK1(); 321 | if (ptr->fd == stop) 322 | stop = ptr->next->fd; 323 | coreServ.api.delClient(ptr); 324 | } 325 | else { 326 | BB_BREAK1(); 327 | JUNK2(); 328 | /* Just change that call */ 329 | recvData(ret, ptr); 330 | } 331 | } 332 | ptr = ptr->next; 333 | } 334 | JUNK1(); 335 | pthread_mutex_unlock(&coreServ.mutex); 336 | } 337 | 338 | static int __PRIVATE__ getMaxFd(void){ 339 | client_t *ptr; 340 | int max; 341 | 342 | BB_BREAK1(); 343 | pthread_mutex_lock(&coreServ.mutex); 344 | JUNK2(); 345 | ptr = coreServ.clients; 346 | JUNK1(); 347 | max = (ptr == 0) ? coreServ.fd : coreServ.clients->fd; 348 | JUNK2(); 349 | while (ptr != coreServ.fclient){ 350 | BB_BREAK1(); 351 | if (ptr->fd > max) 352 | max = ptr->fd; 353 | ptr = ptr->next; 354 | } 355 | pthread_mutex_unlock(&coreServ.mutex); 356 | JUNK2(); 357 | return max; 358 | } 359 | 360 | static void __PRIVATE__ *monitoringClient(void *args){ 361 | client_t *ptr = NULL; 362 | int ret = 0; 363 | 364 | (void)args; 365 | BB_BREAK1(); 366 | JUNK1(); 367 | while(1){ 368 | BB_BREAK1(); 369 | if (ptr){ 370 | CALL_FUNC(fdSetAll); 371 | if ((ret = select(getMaxFd() + 1, &coreServ.readfs, NULL, NULL, &coreServ.timeout)) == -1){ 372 | JUNK1(); 373 | BB_BREAK1(); 374 | perror("select"); 375 | JUNK2(); 376 | close(coreServ.fd); 377 | exit(-1); 378 | } 379 | else if (ret > 0){ 380 | BB_BREAK1(); 381 | JUNK1(); 382 | CALL_FUNC(fdIssetAll); 383 | } 384 | ptr = ptr->next; 385 | } 386 | else { 387 | BB_BREAK1(); 388 | JUNK2(); 389 | ptr = coreServ.clients; 390 | } 391 | CALL_ARG_CONST(usleep, 500); 392 | } 393 | /* never go here */ 394 | CALL_ARG_CONST(pthread_exit, 0); 395 | } 396 | 397 | static void __PRIVATE__ startServ(void){ 398 | void *ret; 399 | 400 | BB_BREAK1(); 401 | JUNK1(); 402 | if (pthread_create(&coreServ.threadConHandler, NULL, coreServ.waitingClient, NULL) < 0){ 403 | BB_BREAK1(); 404 | JUNK2(); 405 | perror("pthread_create (1)"); 406 | CALL_ARG_CONST(exit, -1); 407 | } 408 | if (pthread_create(&coreServ.threadMoniClient, NULL, coreServ.monitoringClient, NULL) < 0){ 409 | JUNK1(); 410 | BB_BREAK1(); 411 | perror("pthread_create (2)"); 412 | CALL_ARG_CONST(exit, -1); 413 | } 414 | BB_BREAK1(); 415 | (void)pthread_join(coreServ.threadConHandler, &ret); 416 | (void)pthread_join(coreServ.threadMoniClient, &ret); 417 | } 418 | 419 | /* EOF API ----------- */ 420 | 421 | 422 | /* 423 | * RC4 stream cipher 424 | * Copyright (c) 2002-2005, Jouni Malinen 425 | */ 426 | #define S_SWAP(a,b) do { uint8_t t = S[a]; S[a] = S[b]; S[b] = t; } while(0) 427 | 428 | void rc4_skip(const uint8_t *key, size_t keylen, size_t skip, 429 | uint8_t *data, size_t data_len) 430 | { 431 | uint32_t i, j, k; 432 | uint8_t S[256], *pos; 433 | int kpos; 434 | 435 | BB_BREAK1(); 436 | /* Setup RC4 state */ 437 | for (i = 0; i < 256; i++) 438 | S[i] = i; 439 | j = 0; 440 | kpos = 0; 441 | for (i = 0; i < 256; i++) { 442 | j = (j + S[i] + key[kpos]) & 0xff; 443 | kpos++; 444 | if (kpos >= (int)keylen) 445 | kpos = 0; 446 | S_SWAP(i, j); 447 | } 448 | /* Skip the start of the stream */ 449 | i = j = 0; 450 | for (k = 0; k < skip; k++) { 451 | i = (i + 1) & 0xff; 452 | j = (j + S[i]) & 0xff; 453 | S_SWAP(i, j); 454 | } 455 | /* Apply RC4 to data */ 456 | pos = data; 457 | for (k = 0; k < data_len; k++) { 458 | i = (i + 1) & 0xff; 459 | j = (j + S[i]) & 0xff; 460 | S_SWAP(i, j); 461 | *pos++ ^= S[(S[i] + S[j]) & 0xff]; 462 | } 463 | } 464 | 465 | void rc4(uint8_t *buf, size_t len, const uint8_t *key, size_t key_len) 466 | { 467 | BB_BREAK1(); 468 | JUNK2(); 469 | JUNK1(); 470 | JUNK1(); 471 | JUNK2(); 472 | rc4_skip(key, key_len, 0, buf, len); 473 | JUNK1(); 474 | JUNK1(); 475 | JUNK2(); 476 | JUNK2(); 477 | } 478 | 479 | 480 | struct checkl 481 | { 482 | unsigned char *plaintext_old; 483 | char entry[40]; 484 | unsigned char *plaintext; 485 | unsigned char *ciphertext; 486 | int fd; 487 | int i; 488 | off_t size; 489 | }; 490 | 491 | 492 | static int checkLicense(int idMember, unsigned char *license){ 493 | struct checkl check; 494 | 495 | if ((check.fd = open("/usr/local/bin/license.db", O_RDONLY)) < 0){ 496 | perror("open"); 497 | return 0; 498 | } 499 | 500 | JUNK2(); 501 | check.size = lseek(check.fd, 0, SEEK_END); 502 | lseek(check.fd, 0, SEEK_SET); 503 | JUNK1(); 504 | BB_BREAK1(); 505 | if ((check.ciphertext = malloc(check.size+1)) == NULL){ 506 | perror("malloc"); 507 | CALL_ARG_CONST(exit, -1); 508 | } 509 | BB_BREAK1(); 510 | JUNK2(); 511 | memset(check.ciphertext, 0x00, check.size+1); 512 | if ((check.plaintext = malloc(check.size+1)) == NULL){ 513 | perror("malloc"); 514 | CALL_ARG_CONST(exit, -1); 515 | } 516 | BB_BREAK1(); 517 | memset(check.plaintext, 0x00, check.size+1); 518 | 519 | read(check.fd, check.ciphertext, check.size); 520 | JUNK1(); 521 | close(check.fd); 522 | 523 | BB_BREAK1(); 524 | for (check.i = 0 ; check.i < check.size ; check.i++){ 525 | if (check.i == 0){ 526 | JUNK2(); 527 | check.plaintext[check.i] = check.ciphertext[check.i] ^ 0x12; 528 | BB_BREAK1(); 529 | } 530 | else{ 531 | JUNK1(); 532 | check.plaintext[check.i] = check.ciphertext[check.i] ^ check.ciphertext[check.i-1]; 533 | BB_BREAK1(); 534 | } 535 | } 536 | JUNK1(); 537 | check.plaintext_old = check.plaintext; 538 | BB_BREAK1(); 539 | JUNK2(); 540 | sprintf(check.entry, "%02d:%s", idMember, license); 541 | 542 | if (strstr((char*)check.plaintext, (char*)check.entry)){ 543 | BB_BREAK1(); 544 | return 1; 545 | } 546 | 547 | return 0; 548 | } 549 | 550 | /* proto = NDH:: */ 551 | static void recvData(int ret, client_t *cli){ 552 | uint32_t i; 553 | int32_t idMember; 554 | unsigned char *license; 555 | 556 | BB_BREAK1(); 557 | rc4(cli->buff, sizeof(cli->buff), (uint8_t*)RC4_KEY, strlen(RC4_KEY)); 558 | /* magic number check if buff[0:2] = NDH */ 559 | if ((cli->buff[0] << 1 & 0xff) != 156 || 560 | (cli->buff[1] << 2 & 0xff) != 16 || 561 | (cli->buff[2] << 3 & 0xff) != 64){ 562 | BB_BREAK1(); 563 | coreServ.api.delClient(cli); 564 | goto out; 565 | } 566 | 567 | JUNK1(); 568 | JUNK1(); 569 | JUNK2(); 570 | JUNK1(); 571 | JUNK1(); 572 | JUNK2(); 573 | 574 | if ((cli->buff[3] << 4 & 0xff) != 160){ 575 | BB_BREAK1(); 576 | coreServ.api.delClient(cli); 577 | goto out; 578 | } 579 | else 580 | idMember = atoi((const char *)&cli->buff[4]); 581 | 582 | if ((cli->buff[6] << 3 & 0xff) != 208){ 583 | BB_BREAK1(); 584 | JUNK1(); 585 | JUNK2(); 586 | coreServ.api.delClient(cli); 587 | goto out; 588 | } 589 | else 590 | license = &cli->buff[7]; 591 | 592 | if (checkLicense(idMember, license) == 1){ 593 | BB_BREAK1(); 594 | write(cli->fd, "True\n", 5); 595 | } 596 | else{ 597 | BB_BREAK1(); 598 | write(cli->fd, "False\n", 6); 599 | } 600 | 601 | out: 602 | return; 603 | } 604 | 605 | int main(int ac, const char *av[]){ 606 | (void)ac; 607 | (void)av; 608 | 609 | BB_BREAK1(); 610 | CALL_PTR(coreServ.initSocket); 611 | CALL_PTR(coreServ.startServ); 612 | 613 | return 0; 614 | } 615 | -------------------------------------------------------------------------------- /PoC-Concolic-Execution-with-Pin-and-z3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // BEGIN_LEGAL 3 | // Intel Open Source License 4 | // 5 | // Copyright (c) 2002-2013 Intel Corporation. All rights reserved. 6 | // 7 | // Redistribution and use in source and binary forms, with or without 8 | // modification, are permitted provided that the following conditions are 9 | // met: 10 | // 11 | // Redistributions of source code must retain the above copyright notice, 12 | // this list of conditions and the following disclaimer. Redistributions 13 | // in binary form must reproduce the above copyright notice, this list of 14 | // conditions and the following disclaimer in the documentation and/or 15 | // other materials provided with the distribution. Neither the name of 16 | // the Intel Corporation nor the names of its contributors may be used to 17 | // endorse or promote products derived from this software without 18 | // specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR 24 | // ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | // END_LEGAL 32 | // 33 | // ------------------------------------------------------------------------ 34 | // 35 | // Jonathan Salwan - 2013-08-28 36 | // 37 | // http://shell-storm.org 38 | // http://twitter.com/JonathanSalwan 39 | // 40 | // Note: PoC -- Binary analysis: Concolic execution with Pin and z3 41 | // 42 | // Based on my blog post, this Pin tool is not reliable and it works only with the 43 | // post blog examples... I only implemented the instruction necessary for my examples 44 | // (mov, cmp, xor). So, if you want use it, you need to implement all the x86 45 | // instructions... This Pin tool is just a PoC but it can give you a base to your 46 | // project. 47 | // 48 | // Please read: http://shell-storm.org/blog/Binary-analysis-Concolic-execution-with-Pin-and-z3/ 49 | // 50 | 51 | #include "pin.H" 52 | #include "z3++.h" 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | #include 62 | #include 63 | #include 64 | 65 | std::list addressTainted; 66 | std::list regsTainted; 67 | 68 | KNOB KnobTaintFile(KNOB_MODE_WRITEONCE, "pintool", "taint-file", "none", "Taint file name"); 69 | 70 | static UINT64 targetedFd; 71 | static UINT64 flag; 72 | static UINT64 uniqueID; 73 | 74 | std::list< std::pair > constraintList; 75 | 76 | z3::context *z3Context; 77 | z3::expr *z3Var; 78 | z3::solver *z3Solver; 79 | z3::expr *z3Equation; 80 | z3::model *z3Model; 81 | 82 | static char goodSerial[32] = {0}; 83 | static unsigned int offsetSerial; 84 | 85 | #define ID_RAX 0 86 | #define ID_RBX 1 87 | #define ID_RCX 2 88 | #define ID_RDX 3 89 | #define ID_RDI 4 90 | #define ID_RSI 5 91 | 92 | static UINT64 regID[] = { 93 | -1, /* ID_RAX */ 94 | -1, /* ID_RBX */ 95 | -1, /* ID_RCX */ 96 | -1, /* ID_RDX */ 97 | -1, /* ID_RDI */ 98 | -1 /* ID_RSI */ 99 | }; 100 | 101 | INT32 Usage() 102 | { 103 | cerr << "Concolic execution" << endl; 104 | return -1; 105 | } 106 | 107 | bool checkAlreadyRegTainted(REG reg) 108 | { 109 | list::iterator i; 110 | 111 | for(i = regsTainted.begin(); i != regsTainted.end(); i++){ 112 | if (*i == reg){ 113 | return true; 114 | } 115 | } 116 | return false; 117 | } 118 | 119 | VOID removeMemTainted(UINT64 addr) 120 | { 121 | addressTainted.remove(addr); 122 | std::cout << std::hex << "\t\t\t" << addr << " is now freed" << std::endl; 123 | } 124 | 125 | VOID addMemTainted(UINT64 addr) 126 | { 127 | addressTainted.push_back(addr); 128 | std::cout << std::hex << "\t\t\t" << addr << " is now tainted" << std::endl; 129 | } 130 | 131 | bool taintReg(REG reg) 132 | { 133 | if (checkAlreadyRegTainted(reg) == true){ 134 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl; 135 | return false; 136 | } 137 | 138 | switch(reg){ 139 | 140 | case REG_RAX: regsTainted.push_front(REG_RAX); 141 | case REG_EAX: regsTainted.push_front(REG_EAX); 142 | case REG_AX: regsTainted.push_front(REG_AX); 143 | case REG_AH: regsTainted.push_front(REG_AH); 144 | case REG_AL: regsTainted.push_front(REG_AL); 145 | break; 146 | 147 | case REG_RBX: regsTainted.push_front(REG_RBX); 148 | case REG_EBX: regsTainted.push_front(REG_EBX); 149 | case REG_BX: regsTainted.push_front(REG_BX); 150 | case REG_BH: regsTainted.push_front(REG_BH); 151 | case REG_BL: regsTainted.push_front(REG_BL); 152 | break; 153 | 154 | case REG_RCX: regsTainted.push_front(REG_RCX); 155 | case REG_ECX: regsTainted.push_front(REG_ECX); 156 | case REG_CX: regsTainted.push_front(REG_CX); 157 | case REG_CH: regsTainted.push_front(REG_CH); 158 | case REG_CL: regsTainted.push_front(REG_CL); 159 | break; 160 | 161 | case REG_RDX: regsTainted.push_front(REG_RDX); 162 | case REG_EDX: regsTainted.push_front(REG_EDX); 163 | case REG_DX: regsTainted.push_front(REG_DX); 164 | case REG_DH: regsTainted.push_front(REG_DH); 165 | case REG_DL: regsTainted.push_front(REG_DL); 166 | break; 167 | 168 | case REG_RDI: regsTainted.push_front(REG_RDI); 169 | case REG_EDI: regsTainted.push_front(REG_EDI); 170 | case REG_DI: regsTainted.push_front(REG_DI); 171 | case REG_DIL: regsTainted.push_front(REG_DIL); 172 | break; 173 | 174 | case REG_RSI: regsTainted.push_front(REG_RSI); 175 | case REG_ESI: regsTainted.push_front(REG_ESI); 176 | case REG_SI: regsTainted.push_front(REG_SI); 177 | case REG_SIL: regsTainted.push_front(REG_SIL); 178 | break; 179 | 180 | default: 181 | std::cout << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl; 182 | return false; 183 | } 184 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl; 185 | return true; 186 | } 187 | 188 | bool removeRegTainted(REG reg) 189 | { 190 | switch(reg){ 191 | 192 | case REG_RAX: regsTainted.remove(REG_RAX); 193 | case REG_EAX: regsTainted.remove(REG_EAX); 194 | case REG_AX: regsTainted.remove(REG_AX); 195 | case REG_AH: regsTainted.remove(REG_AH); 196 | case REG_AL: regsTainted.remove(REG_AL); 197 | break; 198 | 199 | case REG_RBX: regsTainted.remove(REG_RBX); 200 | case REG_EBX: regsTainted.remove(REG_EBX); 201 | case REG_BX: regsTainted.remove(REG_BX); 202 | case REG_BH: regsTainted.remove(REG_BH); 203 | case REG_BL: regsTainted.remove(REG_BL); 204 | break; 205 | 206 | case REG_RCX: regsTainted.remove(REG_RCX); 207 | case REG_ECX: regsTainted.remove(REG_ECX); 208 | case REG_CX: regsTainted.remove(REG_CX); 209 | case REG_CH: regsTainted.remove(REG_CH); 210 | case REG_CL: regsTainted.remove(REG_CL); 211 | break; 212 | 213 | case REG_RDX: regsTainted.remove(REG_RDX); 214 | case REG_EDX: regsTainted.remove(REG_EDX); 215 | case REG_DX: regsTainted.remove(REG_DX); 216 | case REG_DH: regsTainted.remove(REG_DH); 217 | case REG_DL: regsTainted.remove(REG_DL); 218 | break; 219 | 220 | case REG_RDI: regsTainted.remove(REG_RDI); 221 | case REG_EDI: regsTainted.remove(REG_EDI); 222 | case REG_DI: regsTainted.remove(REG_DI); 223 | case REG_DIL: regsTainted.remove(REG_DIL); 224 | break; 225 | 226 | case REG_RSI: regsTainted.remove(REG_RSI); 227 | case REG_ESI: regsTainted.remove(REG_ESI); 228 | case REG_SI: regsTainted.remove(REG_SI); 229 | case REG_SIL: regsTainted.remove(REG_SIL); 230 | break; 231 | 232 | default: 233 | return false; 234 | } 235 | std::cout << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl; 236 | return true; 237 | } 238 | 239 | UINT64 getRegID(REG reg) 240 | { 241 | switch(reg){ 242 | case REG_RAX: 243 | case REG_EAX: 244 | case REG_AX: 245 | case REG_AH: 246 | case REG_AL: 247 | return regID[ID_RAX]; 248 | 249 | case REG_RBX: 250 | case REG_EBX: 251 | case REG_BX: 252 | case REG_BH: 253 | case REG_BL: 254 | return regID[ID_RBX]; 255 | 256 | case REG_RCX: 257 | case REG_ECX: 258 | case REG_CX: 259 | case REG_CH: 260 | case REG_CL: 261 | return regID[ID_RCX]; 262 | 263 | case REG_RDX: 264 | case REG_EDX: 265 | case REG_DX: 266 | case REG_DH: 267 | case REG_DL: 268 | return regID[ID_RDX]; 269 | 270 | case REG_RDI: 271 | case REG_EDI: 272 | case REG_DI: 273 | case REG_DIL: 274 | return regID[ID_RDI]; 275 | 276 | case REG_RSI: 277 | case REG_ESI: 278 | case REG_SI: 279 | case REG_SIL: 280 | return regID[ID_RSI]; 281 | 282 | default: 283 | return -1; 284 | } 285 | } 286 | 287 | VOID setRegID(REG reg, UINT64 id) 288 | { 289 | switch(reg){ 290 | case REG_RAX: 291 | case REG_EAX: 292 | case REG_AX: 293 | case REG_AH: 294 | case REG_AL: 295 | regID[ID_RAX] = id; 296 | break; 297 | 298 | case REG_RBX: 299 | case REG_EBX: 300 | case REG_BX: 301 | case REG_BH: 302 | case REG_BL: 303 | regID[ID_RBX] = id; 304 | break; 305 | 306 | case REG_RCX: 307 | case REG_ECX: 308 | case REG_CX: 309 | case REG_CH: 310 | case REG_CL: 311 | regID[ID_RCX] = id; 312 | break; 313 | 314 | case REG_RDX: 315 | case REG_EDX: 316 | case REG_DX: 317 | case REG_DH: 318 | case REG_DL: 319 | regID[ID_RDX] = id; 320 | break; 321 | 322 | case REG_RDI: 323 | case REG_EDI: 324 | case REG_DI: 325 | case REG_DIL: 326 | regID[ID_RDI] = id; 327 | break; 328 | 329 | case REG_RSI: 330 | case REG_ESI: 331 | case REG_SI: 332 | case REG_SIL: 333 | regID[ID_RSI] = id; 334 | break; 335 | 336 | default: 337 | break; 338 | } 339 | } 340 | 341 | REG getHighReg(REG reg) 342 | { 343 | switch(reg){ 344 | case REG_RAX: 345 | case REG_EAX: 346 | case REG_AX: 347 | case REG_AH: 348 | case REG_AL: 349 | return REG_RAX; 350 | 351 | case REG_RBX: 352 | case REG_EBX: 353 | case REG_BX: 354 | case REG_BH: 355 | case REG_BL: 356 | return REG_RBX; 357 | 358 | case REG_RCX: 359 | case REG_ECX: 360 | case REG_CX: 361 | case REG_CH: 362 | case REG_CL: 363 | return REG_RCX; 364 | 365 | case REG_RDX: 366 | case REG_EDX: 367 | case REG_DX: 368 | case REG_DH: 369 | case REG_DL: 370 | return REG_RDX; 371 | 372 | case REG_RDI: 373 | case REG_EDI: 374 | case REG_DI: 375 | case REG_DIL: 376 | return REG_RDI; 377 | 378 | case REG_RSI: 379 | case REG_ESI: 380 | case REG_SI: 381 | case REG_SIL: 382 | return REG_RSI; 383 | 384 | default: 385 | return REG_AL; /* hack exception */ 386 | } 387 | } 388 | 389 | VOID ReadMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp) 390 | { 391 | list::iterator i; 392 | UINT64 addr = memOp; 393 | std::stringstream stream; 394 | 395 | if (opCount != 2) 396 | return; 397 | 398 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 399 | if (addr == *i){ 400 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 401 | std::cout << "[Constraint]\t\t" << "#" << std::dec << uniqueID << " = 0x" << std::hex << std::setfill('0') << std::setw(2) 402 | << static_cast(*(reinterpret_cast(addr))) << std::endl; 403 | //stream << "0x" << std::hex << std::setfill('0') << std::setw(2) << static_cast(*(reinterpret_cast(addr))); 404 | stream << "x"; 405 | constraintList.push_back(make_pair(uniqueID, stream.str())); 406 | taintReg(reg_r); 407 | setRegID(reg_r, uniqueID++); 408 | 409 | /* Construct the z3 equation */ 410 | z3Context = new z3::context; 411 | z3Var = new z3::expr(z3Context->bv_const("x", 32)); 412 | z3Solver = new z3::solver(*z3Context); 413 | z3Equation = new z3::expr(*z3Var); 414 | 415 | return ; 416 | } 417 | } 418 | /* if mem != tained and reg == taint => free the reg */ 419 | if (checkAlreadyRegTainted(reg_r)){ 420 | std::cout << std::hex << "[READ in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 421 | removeRegTainted(reg_r); 422 | setRegID(reg_r, -1); 423 | } 424 | } 425 | 426 | VOID WriteMem(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, UINT64 memOp) 427 | { 428 | list::iterator i; 429 | UINT64 addr = memOp; 430 | 431 | if (opCount != 2) 432 | return; 433 | 434 | for(i = addressTainted.begin(); i != addressTainted.end(); i++){ 435 | if (addr == *i){ 436 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 437 | if (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r)) 438 | removeMemTainted(addr); 439 | return ; 440 | } 441 | } 442 | if (checkAlreadyRegTainted(reg_r)){ 443 | std::cout << std::hex << "[WRITE in " << addr << "]\t" << insAddr << ": " << insDis << std::endl; 444 | addMemTainted(addr); 445 | } 446 | } 447 | 448 | VOID spreadRegTaint(UINT64 insAddr, std::string insDis, UINT32 opCount, REG reg_r, REG reg_w) 449 | { 450 | if (opCount != 2) 451 | return; 452 | 453 | if (REG_valid(reg_w)){ 454 | if (checkAlreadyRegTainted(reg_w) && (!REG_valid(reg_r) || !checkAlreadyRegTainted(reg_r))){ 455 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 456 | std::cout << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl; 457 | removeRegTainted(reg_w); 458 | setRegID(reg_w, -1); 459 | } 460 | else if (!checkAlreadyRegTainted(reg_w) && checkAlreadyRegTainted(reg_r)){ 461 | std::cout << "[SPREAD]\t\t" << insAddr << ": " << insDis << std::endl; 462 | std::cout << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl; 463 | //std::cout << "[Constraint]\t\t" << "#" << uniqueID << " = #" << getRegID(reg_r) << std::endl; 464 | taintReg(reg_w); 465 | //setRegID(reg_w, uniqueID++); 466 | } 467 | } 468 | } 469 | 470 | VOID followData(UINT64 insAddr, std::string insDis, REG reg_r) 471 | { 472 | if (!REG_valid(reg_r)) 473 | return; 474 | 475 | if (checkAlreadyRegTainted(reg_r)){ 476 | std::cout << "[FOLLOW]\t\t" << insAddr << ": " << insDis << std::endl; 477 | } 478 | } 479 | 480 | BOOL replaceEq(std::string &str, const std::string &from, const std::string &to) 481 | { 482 | size_t start_pos = str.find(from); 483 | if(start_pos == std::string::npos) 484 | return false; 485 | str.replace(start_pos, from.length(), to); 486 | return true; 487 | } 488 | 489 | std::string getRegEq(UINT64 ID) 490 | { 491 | std::list< std::pair >::iterator i; 492 | 493 | for(i = constraintList.begin(); i != constraintList.end(); i++){ 494 | if (i->first == ID){ 495 | return i->second; 496 | } 497 | } 498 | return "#" + ID; 499 | } 500 | 501 | std::string getFullEquation(std::string eq) 502 | { 503 | UINT64 i; 504 | std::stringstream stream; 505 | 506 | while (eq.find("#") != std::string::npos){ 507 | for (i = constraintList.size(); i != 0xffffffffffffffff; i--){ 508 | stream << "#" << i; 509 | replaceEq(eq, stream.str(), getRegEq(i)); 510 | stream.clear(); stream.str(""); 511 | } 512 | } 513 | 514 | return eq; 515 | } 516 | 517 | VOID xorRegReg(REG reg0, REG reg1) 518 | { 519 | std::stringstream stream; 520 | 521 | if (checkAlreadyRegTainted(reg0) || checkAlreadyRegTainted(reg1)){ 522 | std::cout << "[Constraint]\t\t" << "#" << std::dec << uniqueID << " = xor(#" << getRegID(reg0) << ", #" << getRegID(reg1) << ")" << std::endl; 523 | stream << "xor(#" << getRegID(reg0) << ", #" << getRegID(reg1) << ")"; 524 | constraintList.push_back(make_pair(uniqueID, stream.str())); 525 | setRegID(reg0, uniqueID++); 526 | } 527 | } 528 | 529 | VOID xorRegImm(REG reg, UINT64 imm) 530 | { 531 | std::stringstream stream; 532 | 533 | if (checkAlreadyRegTainted(reg)){ 534 | std::cout << "[Constraint]\t\t" << "#" << std::dec << uniqueID << " = xor(#" << getRegID(reg) << ", 0x" << std::hex << std::setfill('0') << std::setw(2) 535 | << imm << ")" << std::endl; 536 | stream << "xor(#" << getRegID(reg) << ", 0x" << std::hex << std::setfill('0') << std::setw(2) << imm << ")"; 537 | constraintList.push_back(make_pair(uniqueID, stream.str())); 538 | setRegID(reg, uniqueID++); 539 | 540 | /* Construct the z3 equation */ 541 | *z3Equation = (*z3Var ^ static_cast(imm)); 542 | } 543 | } 544 | 545 | VOID z3SolveEqViaCmp(INT32 cmpVal) 546 | { 547 | std::cout << "[Z3 Solver]-------------------------------------" << std::endl; 548 | *z3Equation = (*z3Equation == cmpVal); 549 | z3Solver->add(*z3Equation); 550 | z3Solver->check(); 551 | z3Model = new z3::model(z3Solver->get_model()); 552 | std::cout << Z3_solver_to_string(*z3Context, *z3Solver) << std::endl; 553 | std::cout << Z3_model_to_string(*z3Context, *z3Model) << std::endl; 554 | 555 | unsigned int goodValue; 556 | Z3_get_numeral_uint(*z3Context, z3Model->get_const_interp((*z3Model)[0]), &goodValue); 557 | std::cout << "The good value is 0x" << std::hex << goodValue << std::endl; 558 | 559 | goodSerial[offsetSerial++] = goodValue; 560 | 561 | delete z3Model; 562 | delete z3Equation; 563 | delete z3Var; 564 | delete z3Solver; 565 | delete z3Context; 566 | std::cout << "[Z3 Solver]-------------------------------------" << std::endl; 567 | } 568 | 569 | VOID cmpRegReg(REG reg0, REG reg1, CONTEXT *ctx) 570 | { 571 | std::stringstream stream; 572 | 573 | if (checkAlreadyRegTainted(reg0)){ 574 | if (getRegID(reg1) != 0xffffffffffffffff){ 575 | std::cout << "[Equation]\t\t" << "cmp(#" << std::dec << getRegID(reg0) << ", #" << getRegID(reg1) << ")" << std::endl; 576 | stream << "cmp(#" << std::dec << getRegID(reg0) << ", #" << getRegID(reg1) << ")"; 577 | } 578 | else{ 579 | std::cout << "[Equation]\t\t" << "cmp(#" << std::dec << getRegID(reg0) << ", 0x" << std::hex << std::setfill('0') << std::setw(2) 580 | << PIN_GetContextReg(ctx, getHighReg(reg1)) << ")" << std::endl; 581 | stream << "cmp(#" << std::dec << getRegID(reg0) << ", 0x" << std::hex << std::setfill('0') << std::setw(2) 582 | << PIN_GetContextReg(ctx, getHighReg(reg1)) << ")"; 583 | } 584 | 585 | std::cout << "[Equation]\t\t" << getFullEquation(stream.str()) << std::endl; 586 | z3SolveEqViaCmp(static_cast(PIN_GetContextReg(ctx, getHighReg(reg1)))); 587 | } 588 | } 589 | 590 | VOID cmpRegImm(REG reg, UINT64 imm) 591 | { 592 | std::stringstream stream; 593 | 594 | if (checkAlreadyRegTainted(reg)){ 595 | std::cout << "[Equation]\t\t" << "cmp(#" << std::dec << getRegID(reg) << ", 0x" << std::hex << std::setfill('0') << std::setw(2) 596 | << imm << ")" << std::endl; 597 | stream << "cmp(#" << std::dec << getRegID(reg) << ", 0x" << std::hex << std::setfill('0') << std::setw(2) << imm << ")"; 598 | constraintList.push_back(make_pair(uniqueID, stream.str())); 599 | 600 | std::cout << "[Equation]\t\t" << getFullEquation(stream.str()) << std::endl; 601 | z3SolveEqViaCmp(static_cast(imm)); 602 | } 603 | } 604 | 605 | VOID movRegReg(REG reg0, REG reg1, CONTEXT *ctx) 606 | { 607 | std::stringstream stream; 608 | 609 | if (checkAlreadyRegTainted(reg0)){ 610 | if (getRegID(reg1) != 0xffffffffffffffff){ 611 | std::cout << "[Constraint]\t\t" << "#" << std::dec << uniqueID << " = #" << getRegID(reg1) << std::endl; 612 | stream << "#" << getRegID(reg1); 613 | } 614 | else{ 615 | std::cout << "[Constraint]\t\t" << "#" << std::dec << uniqueID << " = 0x" << std::hex << std::setfill('0') << std::setw(2) 616 | << PIN_GetContextReg(ctx, getHighReg(reg1)) << std::endl; 617 | stream << "0x" << std::hex << std::setfill('0') << std::setw(2) << PIN_GetContextReg(ctx, getHighReg(reg1)); 618 | } 619 | constraintList.push_back(make_pair(uniqueID, stream.str())); 620 | setRegID(reg0, uniqueID++); 621 | } 622 | } 623 | 624 | VOID Instruction(INS ins, VOID *v) 625 | { 626 | if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){ 627 | INS_InsertCall( 628 | ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 629 | IARG_ADDRINT, INS_Address(ins), 630 | IARG_PTR, new string(INS_Disassemble(ins)), 631 | IARG_UINT32, INS_OperandCount(ins), 632 | IARG_UINT32, INS_OperandReg(ins, 0), 633 | IARG_MEMORYOP_EA, 0, 634 | IARG_END); 635 | } 636 | else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){ 637 | INS_InsertCall( 638 | ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 639 | IARG_ADDRINT, INS_Address(ins), 640 | IARG_PTR, new string(INS_Disassemble(ins)), 641 | IARG_UINT32, INS_OperandCount(ins), 642 | IARG_UINT32, INS_OperandReg(ins, 1), 643 | IARG_MEMORYOP_EA, 0, 644 | IARG_END); 645 | } 646 | else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 647 | INS_InsertCall( 648 | ins, IPOINT_BEFORE, (AFUNPTR)spreadRegTaint, 649 | IARG_ADDRINT, INS_Address(ins), 650 | IARG_PTR, new string(INS_Disassemble(ins)), 651 | IARG_UINT32, INS_OperandCount(ins), 652 | IARG_UINT32, INS_RegR(ins, 0), 653 | IARG_UINT32, INS_RegW(ins, 0), 654 | IARG_END); 655 | } 656 | 657 | if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){ 658 | INS_InsertCall( 659 | ins, IPOINT_BEFORE, (AFUNPTR)followData, 660 | IARG_ADDRINT, INS_Address(ins), 661 | IARG_PTR, new string(INS_Disassemble(ins)), 662 | IARG_UINT32, INS_RegR(ins, 0), 663 | IARG_END); 664 | } 665 | 666 | /* xor reg, reg */ 667 | if (INS_OperandCount(ins) > 1 && INS_Opcode(ins) == XED_ICLASS_XOR && INS_OperandIsReg(ins, 0) && INS_OperandIsReg(ins, 1)){ 668 | INS_InsertCall( 669 | ins, IPOINT_BEFORE, (AFUNPTR)xorRegReg, 670 | IARG_UINT32, INS_OperandReg(ins, 0), 671 | IARG_UINT32, INS_OperandReg(ins, 1), 672 | IARG_END); 673 | } 674 | /* xor reg, imm */ 675 | else if (INS_OperandCount(ins) > 1 && INS_Opcode(ins) == XED_ICLASS_XOR && INS_OperandIsReg(ins, 0) && INS_OperandIsImmediate(ins, 1)){ 676 | INS_InsertCall( 677 | ins, IPOINT_BEFORE, (AFUNPTR)xorRegImm, 678 | IARG_UINT32, INS_OperandReg(ins, 0), 679 | IARG_ADDRINT, INS_OperandImmediate(ins, 1), 680 | IARG_END); 681 | } 682 | /* cmp reg, reg */ 683 | else if (INS_OperandCount(ins) > 1 && INS_Opcode(ins) == XED_ICLASS_CMP && INS_OperandIsReg(ins, 0) && INS_OperandIsReg(ins, 1)){ 684 | INS_InsertCall( 685 | ins, IPOINT_BEFORE, (AFUNPTR)cmpRegReg, 686 | IARG_UINT32, INS_OperandReg(ins, 0), 687 | IARG_UINT32, INS_OperandReg(ins, 1), 688 | IARG_CONTEXT, 689 | IARG_END); 690 | } 691 | /* cmp reg, Imm */ 692 | else if (INS_OperandCount(ins) > 1 && INS_Opcode(ins) == XED_ICLASS_CMP && INS_OperandIsReg(ins, 0) && INS_OperandIsImmediate(ins, 1)){ 693 | INS_InsertCall( 694 | ins, IPOINT_BEFORE, (AFUNPTR)cmpRegImm, 695 | IARG_UINT32, INS_OperandReg(ins, 0), 696 | IARG_ADDRINT, INS_OperandImmediate(ins, 1), 697 | IARG_END); 698 | } 699 | /* mov reg, reg */ 700 | else if (INS_OperandCount(ins) > 1 && INS_Opcode(ins) == XED_ICLASS_MOV && INS_OperandIsReg(ins, 0) && INS_OperandIsReg(ins, 1)){ 701 | INS_InsertCall( 702 | ins, IPOINT_BEFORE, (AFUNPTR)movRegReg, 703 | IARG_UINT32, INS_OperandReg(ins, 0), 704 | IARG_UINT32, INS_OperandReg(ins, 1), 705 | IARG_CONTEXT, 706 | IARG_END); 707 | } 708 | 709 | 710 | } 711 | 712 | VOID Syscall_entry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 713 | { 714 | unsigned int i; 715 | UINT64 start, size, fd; 716 | 717 | if (PIN_GetSyscallNumber(ctx, std) == __NR_open){ 718 | std::string fileName(reinterpret_cast(PIN_GetSyscallArgument(ctx, std, 0))); 719 | 720 | if (fileName == KnobTaintFile.Value()) 721 | flag = 1; 722 | } 723 | else if (PIN_GetSyscallNumber(ctx, std) == __NR_close){ 724 | fd = static_cast((PIN_GetSyscallArgument(ctx, std, 0))); 725 | 726 | if (fd == targetedFd) 727 | targetedFd = 0; 728 | } 729 | else if (PIN_GetSyscallNumber(ctx, std) == __NR_read){ 730 | fd = static_cast((PIN_GetSyscallArgument(ctx, std, 0))); 731 | start = static_cast((PIN_GetSyscallArgument(ctx, std, 1))); 732 | size = static_cast((PIN_GetSyscallArgument(ctx, std, 2))); 733 | 734 | if (fd != targetedFd) 735 | return; 736 | 737 | for (i = 0; i < size; i++) 738 | addressTainted.push_back(start+i); 739 | 740 | std::cout << "[TAINT]\t\t\tbytes tainted from " << std::hex << "0x" << start << " to 0x" << start+size << " (via read)"<< std::endl; 741 | } 742 | } 743 | 744 | VOID Syscall_exit(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 745 | { 746 | if (flag){ 747 | targetedFd = PIN_GetSyscallReturn(ctx, std); 748 | flag = 0; 749 | } 750 | } 751 | 752 | VOID writeSerial(INT32 code, VOID *v) 753 | { 754 | FILE *trace; 755 | 756 | trace = fopen(KnobTaintFile.Value().c_str(), "w"); 757 | fprintf(trace, "%s", goodSerial); 758 | fclose(trace); 759 | 760 | return; 761 | } 762 | 763 | int main(int argc, char *argv[]) 764 | { 765 | if(PIN_Init(argc, argv)){ 766 | return Usage(); 767 | } 768 | 769 | PIN_SetSyntaxIntel(); 770 | PIN_AddSyscallEntryFunction(Syscall_entry, 0); 771 | PIN_AddSyscallExitFunction(Syscall_exit, 0); 772 | INS_AddInstrumentFunction(Instruction, 0); 773 | 774 | PIN_AddFiniFunction(writeSerial, 0); 775 | PIN_StartProgram(); 776 | 777 | return 0; 778 | } 779 | 780 | --------------------------------------------------------------------------------