├── .be ├── version ├── settings └── bugs │ ├── 0093b6a7-9114-40ff-a4c1-e9d2faab1dd5 │ └── values │ ├── 48896671-d663-4bb7-8d68-09653faa183e │ └── values │ ├── 9c2b737d-c360-4bac-87f6-679bc9de1c5d │ └── values │ ├── ad2501bc-04c1-4d22-bcdc-66c8e14522d9 │ └── values │ ├── 49d391ca-d55a-476e-ad50-768daa0a5400 │ └── values │ ├── 978dd8f6-fa99-4fe5-a8e3-38069483a770 │ └── values │ ├── 83f1e16d-913f-4989-9a0e-4fce2677ce75 │ └── values │ └── b798bef0-8e85-46a3-9e82-389020a490b2 │ └── values ├── .gitignore ├── shellcode-close-linux-ia32.S ├── HACKING ├── shellcode-test-linux-ia32.S ├── testmodule.cc ├── Makefile ├── asm-constants.h ├── shellcode-dup2-linux-ia32.S ├── closemodule.cc ├── injcode.h ├── ErrHandling.h ├── README ├── inject.h ├── client.c ├── dup2module.cc ├── injcode.cc ├── shellcode-retty-linux-ia32.S ├── inject.cc ├── retty.cc └── LICENSE /.be/version: -------------------------------------------------------------------------------- 1 | Bugs Everywhere Tree 1 0 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | client 3 | injcode 4 | -------------------------------------------------------------------------------- /.be/settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | rcs_name=git 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.be/bugs/0093b6a7-9114-40ff-a4c1-e9d2faab1dd5/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=open 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=ia64 support 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Sat, 24 Jan 2009 18:53:31 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/48896671-d663-4bb7-8d68-09653faa183e/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=open 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=sparc64 support 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Sat, 24 Jan 2009 18:53:39 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/9c2b737d-c360-4bac-87f6-679bc9de1c5d/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=closed 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=proxy window size updates 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Sat, 24 Jan 2009 18:53:59 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/ad2501bc-04c1-4d22-bcdc-66c8e14522d9/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=open 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=EINTR handling in shellcode 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Wed, 04 Mar 2009 14:55:04 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/49d391ca-d55a-476e-ad50-768daa0a5400/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=open 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=make sure it works on linux 2.4.x 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Wed, 04 Mar 2009 10:13:39 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/978dd8f6-fa99-4fe5-a8e3-38069483a770/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=closed 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=close module should have re-open option 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Wed, 04 Mar 2009 11:36:23 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/83f1e16d-913f-4989-9a0e-4fce2677ce75/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=open 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=handle multiprocess stuff, move a whole session 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Sat, 24 Jan 2009 18:54:42 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /.be/bugs/b798bef0-8e85-46a3-9e82-389020a490b2/values: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | creator=Thomas Habets 5 | 6 | 7 | 8 | 9 | 10 | 11 | severity=minor 12 | 13 | 14 | 15 | 16 | 17 | 18 | status=closed 19 | 20 | 21 | 22 | 23 | 24 | 25 | summary=move terminal-code (tcgetattr) to retty module 26 | 27 | 28 | 29 | 30 | 31 | 32 | time=Wed, 04 Mar 2009 10:14:37 +0000 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /shellcode-close-linux-ia32.S: -------------------------------------------------------------------------------- 1 | #if defined(__linux__) && defined(__i386) 2 | /** injcode/shellcode-close-linux-ia32.S 3 | * 4 | * Copyright(c) Thomas Habets 2009 5 | */ 6 | #include "asm-constants.h" 7 | 8 | .globl shellcodeClose 9 | shellcodeClose: 10 | movl $SYS_close, %eax 11 | movl (%ebp), %ebx 12 | int $0x80 13 | xorl %eax, %eax 14 | .globl shellcodeCloseEnd 15 | shellcodeCloseEnd: nop 16 | #endif 17 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | ================= 2 | Injcode hacking 3 | ================= 4 | :Author: Thomas Habets 5 | :Contact: thomas@habets.pp.se 6 | :Copyright: GPL 7 | 8 | 9 | Adding new shellcode 10 | ==================== 11 | * Write shellcode---.S 12 | * Write module.cc 13 | * Add both to Makefile 14 | * Add to injcode() in injcode.cc 15 | * Add class to injcode.h 16 | 17 | Porting shellcode to new architechture 18 | ====================================== 19 | * Rewrite all .S files 20 | * Add them to Makefile 21 | -------------------------------------------------------------------------------- /shellcode-test-linux-ia32.S: -------------------------------------------------------------------------------- 1 | #if defined(__linux__) && defined(__i386) 2 | /** injcode/shellcode-test-linux-ia32.S 3 | * 4 | * Copyright(c) Thomas Habets 2009 5 | */ 6 | #include "asm-constants.h" 7 | 8 | .equ teststr, 0 9 | 10 | .globl shellcodeTest 11 | shellcodeTest: 12 | movl $SYS_write, %eax 13 | movl $2, %ebx # stderr 14 | leal teststr(%ebp), %ecx 15 | movl $10, %edx # len 16 | int $0x80 17 | xorl %eax, %eax 18 | .globl shellcodeTestEnd 19 | shellcodeTestEnd: nop 20 | #endif 21 | -------------------------------------------------------------------------------- /testmodule.cc: -------------------------------------------------------------------------------- 1 | // injcode/testmodule.cc 2 | #include "inject.h" 3 | #include "ErrHandling.h" 4 | #include "injcode.h" 5 | 6 | extern "C" char* shellcodeTest(); 7 | extern "C" char* shellcodeTestEnd(); 8 | 9 | /** 10 | * 11 | */ 12 | TestModule::TestModule(Inject &injector) 13 | :InjMod(injector) 14 | { 15 | char data[injector.pageSize()]; 16 | char code[injector.pageSize()]; 17 | 18 | memset(code, 0x90, injector.pageSize()); 19 | memset(data, 0, injector.pageSize()); 20 | code[injector.pageSize()-1] = 0xcc; 21 | 22 | size_t s = (Inject::ptr_t)shellcodeTestEnd 23 | - (Inject::ptr_t)shellcodeTest; 24 | //printf("Shellcode size is %d\n", s); 25 | memcpy(code, (char*)shellcodeTest, s); 26 | strcpy(data, "Inject OK\n"); 27 | 28 | injector.inject(code, data); 29 | } 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # injcode/Makefile 2 | # 3 | CXXFLAGS=-g -W -Wall -pipe -O2 4 | GIT=git 5 | ECHO=echo 6 | SED=sed 7 | GZIP=gzip 8 | TAR=tar 9 | GPG=gpg 10 | 11 | all: injcode 12 | 13 | injcode: injcode.o \ 14 | inject.o \ 15 | retty.o \ 16 | testmodule.o \ 17 | closemodule.o \ 18 | dup2module.o \ 19 | shellcode-test-linux-ia32.o \ 20 | shellcode-close-linux-ia32.o \ 21 | shellcode-dup2-linux-ia32.o \ 22 | shellcode-retty-linux-ia32.o 23 | $(CXX) $(CXXFLAGS) -o $@ $^ -lutil 24 | 25 | injcode-%.tar.gz: 26 | $(GIT) archive --format=tar \ 27 | --prefix=$(shell $(ECHO) $@ | $(SED) 's/\.tar\.gz//')/ \ 28 | injcode-$(shell $(ECHO) $@|$(SED) 's/.*-//'|$(SED) 's/\.tar\.gz//') \ 29 | | $(TAR) --delete injcode-$(shell $(ECHO) $@|$(SED) 's/.*-//'|$(SED) 's/\.tar\.gz//')/.be | $(GZIP) -9 > $@ 30 | $(GPG) -b -a $@ 31 | 32 | pt: 33 | g++ -Wall -W -g -o pt pt.cc shellcode-linux-ia32.S -lutil 34 | b.s: 35 | gcc -c -g -Wa,-a,-ad b.c > b.lst 36 | 37 | clean: 38 | rm -f *.o injcode 39 | -------------------------------------------------------------------------------- /asm-constants.h: -------------------------------------------------------------------------------- 1 | /** injcode/asm-constants.h 2 | * 3 | * Copyright(c) Thomas Habets 2009 4 | */ 5 | #ifdef __linux__ 6 | /* 7 | Syscall numbers http://foosec.pl/pub/info/syscalls_linux_2_2.html 8 | */ 9 | .equ SYS_fork, 2 10 | .equ SYS_read, 3 11 | .equ SYS_write, 4 12 | .equ SYS_open, 5 13 | .equ SYS_close, 6 14 | .equ SYS_waitpid, 7 15 | .equ SYS_kill, 37 16 | .equ SYS_ioctl, 54 17 | .equ SYS_setpgid, 57 18 | .equ SYS_dup2, 63 19 | .equ SYS_setsid, 66 20 | .equ SYS_socketcall, 102 21 | 22 | .equ SC_socket, 1 23 | .equ SC_connect, 3 24 | .equ SC_recvmsg, 17 25 | 26 | .equ TIOCSCTTY, 0x540E 27 | .equ TIOCNOTTY, 0x5422 28 | .equ TCGETS, 0x5401 29 | .equ TCSETS, 0x5402 30 | 31 | .equ SIGKILL, 9 32 | .equ SIGWINCH, 28 33 | #endif 34 | -------------------------------------------------------------------------------- /shellcode-dup2-linux-ia32.S: -------------------------------------------------------------------------------- 1 | #if defined(__linux__) && defined(__i386) 2 | /** injcode/shellcode-dup2-linux-ia32.S 3 | * 4 | * Copyright(c) Thomas Habets 2009 5 | */ 6 | #include "asm-constants.h" 7 | 8 | .globl shellcodeDup2 9 | shellcodeDup2: 10 | # open() 11 | movl $SYS_open, %eax 12 | leal 12(%ebp), %ebx 13 | movl 4(%ebp), %ecx 14 | movl 8(%ebp), %edx 15 | int $0x80 16 | cmpl $0, %eax 17 | jl .Lerrout_open 18 | movl %eax, %ebx 19 | 20 | # dup2() 21 | movl $SYS_dup2, %eax 22 | movl (%ebp), %ecx 23 | int $0x80 24 | cmpl $0, %eax 25 | jl .Lerrout_dup2 26 | 27 | # close() 28 | movl $SYS_close, %eax 29 | int $0x80 30 | cmpl $0, %eax 31 | jl .Lerrout_close 32 | 33 | # all done 34 | xorl %eax, %eax 35 | jmp shellcodeDup2End 36 | 37 | .Lerrout_close: 38 | .Lerrout_dup2: 39 | movl $SYS_close, %eax 40 | int $0x80 41 | .Lerrout_open: 42 | 43 | .globl shellcodeDup2End 44 | shellcodeDup2End: nop 45 | #endif 46 | -------------------------------------------------------------------------------- /closemodule.cc: -------------------------------------------------------------------------------- 1 | // injcode/closemodule.cc 2 | #include 3 | 4 | #include "inject.h" 5 | #include "ErrHandling.h" 6 | #include "injcode.h" 7 | 8 | extern options_t options; 9 | 10 | extern "C" char* shellcodeClose(); 11 | extern "C" char* shellcodeCloseEnd(); 12 | 13 | /** 14 | * 15 | * Shellcode data: 16 | * Size Value 17 | * sizeof(int) fd to close 18 | * 19 | */ 20 | CloseModule::CloseModule(Inject &injector) 21 | :InjMod(injector) 22 | { 23 | char data[injector.pageSize()]; 24 | char code[injector.pageSize()]; 25 | 26 | // sanity check input 27 | if (!options.parameters.count("fd")) { 28 | throw ErrMalformed("CloseModule::CloseModule()", 29 | "Close module requires option -ofd="); 30 | } 31 | 32 | // init 33 | memset(code, 0x90, injector.pageSize()); 34 | memset(data, 0, injector.pageSize()); 35 | code[injector.pageSize()-1] = 0xcc; 36 | 37 | // data setup 38 | *((int*)data) = strtoul(options.parameters["fd"].c_str(), NULL, 0); 39 | 40 | // code setup 41 | size_t s = (Inject::ptr_t)shellcodeCloseEnd 42 | - (Inject::ptr_t)shellcodeClose; 43 | memcpy(code, (char*)shellcodeClose, s); 44 | 45 | // execute 46 | injector.inject(code, data); 47 | } 48 | -------------------------------------------------------------------------------- /injcode.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | class InjMod: public ErrHandling { 10 | protected: 11 | Inject &injector; 12 | InjMod(const InjMod&); 13 | InjMod&operator=(const InjMod&); 14 | public: 15 | InjMod(Inject&injector):injector(injector) {} 16 | virtual void run() = 0; 17 | virtual ~InjMod() {}; 18 | }; 19 | 20 | class TestModule: public InjMod { 21 | public: 22 | TestModule(Inject&); 23 | void run() {}; 24 | }; 25 | class CloseModule: public InjMod { 26 | public: 27 | CloseModule(Inject&); 28 | void run() {}; 29 | }; 30 | class Dup2Module: public InjMod { 31 | public: 32 | Dup2Module(Inject&); 33 | void run() {}; 34 | }; 35 | class Retty: public InjMod { 36 | struct termios orig_tio; 37 | int send_fds(int sd, int proxyfd); 38 | void child(int proxyfd); 39 | std::string readFd(int fd); 40 | void setRawTerminal(int fd); 41 | void setupPty(); 42 | static void sigwinch(int); 43 | public: 44 | Retty(Inject&); 45 | ~Retty(); 46 | void run(); 47 | }; 48 | 49 | 50 | typedef struct { 51 | int targetpid; 52 | int verbose; 53 | std::string moduleName; 54 | std::auto_ptr module; 55 | const char *argv0; 56 | std::map parameters; 57 | } options_t; 58 | -------------------------------------------------------------------------------- /ErrHandling.h: -------------------------------------------------------------------------------- 1 | // -*- c++ -*- 2 | #ifndef __INCLUDE_ERRHANDLING_H__ 3 | #define __INCLUDE_ERRHANDLING_H__ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class ErrHandling { 10 | public: 11 | class ErrBase: public std::exception { 12 | protected: 13 | const std::string func; 14 | const std::string msg; 15 | std::string huh; 16 | public: 17 | ErrBase(const std::string &func, 18 | const std::string &msg) 19 | :func(func),msg(msg) 20 | { 21 | huh = func + ": " + msg; 22 | } 23 | virtual ~ErrBase() throw() {} 24 | const char *what() const throw() { return huh.c_str(); }; 25 | const char *whatMsg() const throw() { return msg.c_str(); }; 26 | }; 27 | class ErrMalformed: public ErrBase { 28 | public: 29 | ErrMalformed(const std::string &func, 30 | const std::string &msg) 31 | :ErrBase(func, msg) { } 32 | }; 33 | class ErrSys: public ErrBase { 34 | protected: 35 | const std::string sys; 36 | int err; 37 | public: 38 | ErrSys(const std::string &func, 39 | const std::string &sys, 40 | const std::string &msg = "") 41 | :ErrBase(func, msg),sys(sys) 42 | { 43 | err = errno; 44 | huh = func + ": " 45 | + sys + "(): " 46 | + strerror(errno) + ": " 47 | + msg; 48 | } 49 | virtual ~ErrSys() throw() {} 50 | }; 51 | 52 | }; 53 | #endif 54 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ========= 2 | Injcode 3 | ========= 4 | :Author: Thomas Habets 5 | :Contact: thomas@habets.pp.se 6 | :Copyright: GPL 7 | 8 | Only supports x86 Linux, not 64bit. 9 | 10 | Install 11 | ======= 12 | Just type "make", and then put the binary (injcode) wherever you like. 13 | 14 | How it works 15 | ============ 16 | Injcode attaches to the target process using ptrace(). It then copies code 17 | and data into the memory space of the process and runs that. Then it cleans 18 | up as if it was never there. 19 | 20 | It places the code and data in the current code and data page, respectively. 21 | This ensures that no stack execution protection blocks it. 22 | 23 | The code injected can be anything, but currently these are implemented: 24 | - test Prints a message to stdout in the context of the target process. 25 | - close Close any file descriptor. (see /proc//fd) 26 | - dup2 Overwrite any fd with a newly opened file. 27 | - retty Move a program from another tty to this one. 28 | 29 | Doing retty is quite involved. See: 30 | http://blog.habets.pp.se/2009/03/Moving-a-process-to-another-terminal 31 | for the full story. 32 | 33 | Running 34 | ======= 35 | 36 | Example 1: move irssi from one terminal to another 37 | -------------------------------------------------- 38 | Maybe move it into a screen. 39 | 40 | First start irssi in one terminal. 41 | 42 | Run injcode in another terminal: 43 | $ injcode -m retty 44 | 45 | Irssi should now be moved to the second terminal, including having a new 46 | controlling terminal. 47 | 48 | Example 2: redirect stdout of a running program into a file 49 | ----------------------------------------------------------- 50 | $ injcode -m dup2 \ 51 | -ofd=1 \ 52 | -oflags=O_CREAT,O_WRONLY,O_TRUNC \ 53 | -ofilename=logfile.txt 54 | 55 | Bugs 56 | ==== 57 | See bug list/wishist using BugsEverywhere. 58 | 59 | 60 | This file is written in 61 | `reStructuredText `_ 62 | -------------------------------------------------------------------------------- /inject.h: -------------------------------------------------------------------------------- 1 | #include "ErrHandling.h" 2 | 3 | #include 4 | 5 | class Inject: public ErrHandling { 6 | public: 7 | typedef unsigned long ptr_t; 8 | struct user_regs_struct { 9 | long ebx, ecx, edx, esi, edi, ebp, eax; 10 | unsigned short ds, __ds, es, __es; 11 | unsigned short fs, __fs, gs, __gs; 12 | long orig_eax, eip; 13 | unsigned short cs, __cs; 14 | long eflags, esp; 15 | unsigned short ss, __ss; 16 | }; 17 | protected: 18 | int pid; 19 | bool attached; 20 | int verbose; 21 | std::string argv0; 22 | 23 | bool injected; 24 | ptr_t codebase; 25 | ptr_t database; 26 | int pagesize; 27 | struct user_regs_struct oldregs; 28 | 29 | std::vector olddatapage; 30 | std::vector oldcodepage; 31 | 32 | void peekpoke(const char *data, ptr_t addr, size_t len, bool poke); 33 | void peek(const char *data, 34 | ptr_t addr, 35 | size_t len) { peekpoke(data, addr, len, false); } 36 | void poke(const char *data, 37 | ptr_t addr, 38 | size_t len) { peekpoke(data, addr, len, true); } 39 | 40 | public: 41 | class ErrSysPtrace: public ErrSys { 42 | int req; 43 | public: 44 | ErrSysPtrace(const std::string &func, int req, 45 | const std::string &msg) 46 | :ErrSys(func, "ptrace", msg), req(req) { } 47 | }; 48 | 49 | Inject(pid_t pid, int verbose, const char *argv0); 50 | ~Inject(); 51 | 52 | void attach(); 53 | void detach(); 54 | ptr_t codeBase(); 55 | ptr_t dataBase(); 56 | void run(); 57 | void dumpregs(bool onlyIfEAX=false); 58 | int pageSize() { attach(); return pagesize; } 59 | size_t wordSize() { return sizeof(ptr_t); } 60 | 61 | void inject(void *code, void *data); 62 | void uninject(); 63 | }; 64 | -------------------------------------------------------------------------------- /client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | void 12 | doit() 13 | { 14 | __asm__("movl $54, %eax\n" 15 | "movl $0, %ebx\n" 16 | "movl $0x5422, %ecx\n" 17 | "movl $0, %edx\n" 18 | "int $0x80\n"); 19 | } 20 | 21 | void sigint(int a) 22 | { 23 | 24 | } 25 | 26 | void 27 | sigwinch(int unused) 28 | { 29 | printf("Sigwinch!\n"); 30 | } 31 | 32 | 33 | int 34 | main() 35 | { 36 | int n = 0, t; 37 | int pid; 38 | 39 | signal(SIGWINCH, sigwinch); 40 | 41 | if (0) { 42 | doit(); 43 | } 44 | if (0) { 45 | //signal(SIGHUP, sigint); 46 | if (!(pid = fork())) { 47 | //printf("killstop %d\n", kill(getppid(),SIGSTOP)); 48 | //printf("killcont %d\n", kill(getppid(),SIGCONT)); 49 | //printf("C setsid: %d\n", setsid()); 50 | printf("setpgrp(%d): %d\n", pid, setpgid(0, 0)); 51 | for(;;) {sleep(10); } 52 | } 53 | //printf("parent pid %d\n", getpid()); 54 | //sleep(10); 55 | //printf("P setsid: %d\n", setsid()); 56 | } 57 | if (0) { 58 | sleep(10); 59 | printf("setpgrp(%d): %d\n", pid, setpgid(getpid(), pid)); 60 | } 61 | if (0) { 62 | printf("setsid: %d\n", setsid()); 63 | } 64 | if (0) { 65 | t = ioctl(0, TIOCNOTTY, NULL); 66 | printf("ioctl(): %d %s\n", t, strerror(errno)); 67 | } 68 | if (0) { 69 | t = setsid(); 70 | printf("setsid: %d %s\n", t, 71 | strerror(errno)); 72 | } 73 | for(;;) { 74 | struct winsize w; 75 | 76 | if (-1 == ioctl(0, TIOCGWINSZ, &w)) { 77 | fprintf(stderr, "ioctl(TIOCGWINSZ) fail: %s\n", 78 | strerror(errno)); 79 | } 80 | 81 | printf("Loop pid=%d (winsz: %hdx%hd) %d\n", 82 | getpid(), 83 | w.ws_col, w.ws_row, 84 | n++); 85 | //fprintf(stderr, "> lala\n"); 86 | if (1) { 87 | sleep(1); 88 | } else { 89 | getchar(); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /dup2module.cc: -------------------------------------------------------------------------------- 1 | // injcode/dup2module.cc 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "inject.h" 10 | #include "ErrHandling.h" 11 | #include "injcode.h" 12 | 13 | extern options_t options; 14 | 15 | extern "C" char* shellcodeDup2(); 16 | extern "C" char* shellcodeDup2End(); 17 | 18 | std::vector 19 | strSplit(const std::string str, std::string delim) 20 | { 21 | std::vector ret; 22 | std::string s(str); 23 | size_t n; 24 | while ((n = s.find_first_of(delim)) != s.npos) { 25 | if (n > 0) { 26 | ret.push_back(s.substr(0, n)); 27 | } 28 | s = s.substr(n + 1); 29 | } 30 | if (s.length() > 0) { 31 | ret.push_back(s); 32 | } 33 | return ret; 34 | } 35 | /** 36 | * 37 | * Shellcode data: 38 | * Size Value Example cmdline 39 | * sizeof(int) fd to dup2 to -ofd=1 40 | * sizeof(int) open() flags -oflags=O_WRONLY,O_CREAT 41 | * sizeof(mode_t) open() file mode -oflags=0644 (default) 42 | * variable file to open, asciiz -ofilename=newstdout 43 | * 44 | */ 45 | Dup2Module::Dup2Module(Inject &injector) 46 | :InjMod(injector) 47 | { 48 | char data[injector.pageSize()]; 49 | char code[injector.pageSize()]; 50 | 51 | // sanity check input 52 | if (!options.parameters.count("fd") 53 | || !options.parameters.count("flags") 54 | || !options.parameters.count("filename")) { 55 | throw ErrMalformed("Dup2Module::Dup2Module()", 56 | "dup2 requires options fd, " 57 | "flags & filename"); 58 | 59 | } 60 | 61 | // init 62 | memset(code, 0x90, injector.pageSize()); 63 | memset(data, 0, injector.pageSize()); 64 | code[injector.pageSize()-1] = 0xcc; 65 | 66 | // data setup 67 | int *fd, *flags; 68 | fd = &((int*)data)[0]; 69 | flags = &((int*)data)[1]; 70 | *fd = strtoul(options.parameters["fd"].c_str(), NULL, 0); 71 | 72 | std::vector fl=strSplit(options.parameters["flags"],","); 73 | *flags = 0; 74 | for (std::vector::const_iterator itr = fl.begin(); 75 | itr != fl.end(); 76 | ++itr) { 77 | if (*itr == "O_RDONLY") { *flags |= O_RDONLY; } 78 | else if (*itr == "O_WRONLY") { *flags |= O_WRONLY; } 79 | else if (*itr == "O_RDWR") { *flags |= O_RDWR; } 80 | else if (*itr == "O_CREAT") { *flags |= O_CREAT; } 81 | else if (*itr == "O_APPEND") { *flags |= O_APPEND; } 82 | else if (*itr == "O_DIRECTORY") { *flags |= O_DIRECTORY; } 83 | else if (*itr == "O_EXCL") { *flags |= O_EXCL; } 84 | else if (*itr == "O_NONBLOCK") { *flags |= O_NONBLOCK; } 85 | else if (*itr == "O_TRUNC") { *flags |= O_TRUNC; } 86 | else { 87 | throw ErrMalformed("Dup2Module::Dup2Module()", 88 | "Invalid flag " + *itr); 89 | } 90 | } 91 | mode_t *mode = (mode_t*)&((int*)data)[2]; 92 | *mode = 0644; // default mode 93 | if (options.parameters.count("mode")) { 94 | *mode = strtoul(options.parameters["mode"].c_str(), NULL, 0); 95 | } 96 | memcpy(data + sizeof(int) + sizeof(int) + sizeof(mode_t), 97 | options.parameters["filename"].data(), 98 | options.parameters["filename"].length()); 99 | 100 | // code setup 101 | size_t s = (Inject::ptr_t)shellcodeDup2End 102 | - (Inject::ptr_t)shellcodeDup2; 103 | memcpy(code, (char*)shellcodeDup2, s); 104 | 105 | // execute 106 | injector.inject(code, data); 107 | } 108 | -------------------------------------------------------------------------------- /injcode.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "inject.h" 8 | 9 | #include "injcode.h" 10 | options_t options; 11 | 12 | const char* defaultModule = "test"; 13 | const float version = 0.11; 14 | 15 | class ErrModule: public std::exception { 16 | protected: 17 | const std::string func; 18 | const std::string msg; 19 | std::string huh; 20 | public: 21 | ErrModule(const std::string &func, 22 | const std::string &msg) 23 | :func(func),msg(msg) 24 | { 25 | huh = func + ": " + msg; 26 | } 27 | virtual ~ErrModule() throw() {} 28 | const char *what() const throw() { return huh.c_str(); }; 29 | }; 30 | 31 | static void 32 | injcode() 33 | { 34 | Inject injector(options.targetpid, options.verbose, options.argv0); 35 | if (options.moduleName == "retty") { 36 | options.module.reset(new Retty(injector)); 37 | } else if (options.moduleName == "test") { 38 | options.module.reset(new TestModule(injector)); 39 | } else if (options.moduleName == "close") { 40 | options.module.reset(new CloseModule(injector)); 41 | } else if (options.moduleName == "dup2") { 42 | options.module.reset(new Dup2Module(injector)); 43 | } else { 44 | throw ErrModule("injcode", 45 | std::string("Unknown module name: '") 46 | + options.moduleName 47 | + std::string("'\n")); 48 | } 49 | injector.run(); 50 | //injector.dumpregs(options.verbose < 2); 51 | injector.detach(); 52 | options.module->run(); 53 | } 54 | 55 | /** 56 | * 57 | */ 58 | static 59 | void usage(int err) 60 | { 61 | printf("Injcode %.2f, by Thomas Habets \n" 62 | "Usage: %s [ -hv ] [ -m ]\n" 63 | "\t-h Show this help text\n" 64 | "\t-m test/retty/close/dup2. Default: %s\n" 65 | "\t-o= Module-specific parameters\n" 66 | "\t-v Increase verbosity.\n" 67 | "\n" 68 | " Close module\n" 69 | "\t-ofd= File descriptor to close\n" 70 | "\n" 71 | " Dup2 module\n" 72 | "\t-ofd= File descriptor to overwrite\n" 73 | "\t-ofilename= File to open()\n" 74 | "\t-oflags= open() flags\n" 75 | ,version, options.argv0, defaultModule); 76 | exit(err); 77 | } 78 | 79 | int 80 | main(int argc, char **argv) 81 | { 82 | // default options 83 | options.verbose = 0; 84 | options.argv0 = argv[0]; 85 | options.moduleName = defaultModule; 86 | 87 | // option parsing 88 | for(int c = 0; c != -1;) { 89 | switch((c = getopt(argc, argv, "hm:o:v"))) { 90 | case -1: 91 | break; 92 | case 'h': 93 | usage(0); 94 | break; 95 | case 'm': 96 | options.moduleName = optarg; 97 | break; 98 | case 'o': { 99 | char *t = strchr(optarg, '='); 100 | if (!t) { 101 | usage(1); 102 | } 103 | options.parameters[std::string(optarg,t)] 104 | = std::string(t+1); 105 | } 106 | break; 107 | case 'v': 108 | options.verbose++; 109 | break; 110 | default: 111 | usage(1); 112 | break; 113 | } 114 | } 115 | 116 | if (argc != optind + 1) { 117 | usage(1); 118 | } 119 | options.targetpid = atoi(argv[optind]); 120 | 121 | try { 122 | injcode(); 123 | } catch(const Inject::ErrMalformed &e) { 124 | fprintf(stderr, "%s: %s\n", argv[0], e.whatMsg()); 125 | usage(1); 126 | } catch(const Inject::ErrSysPtrace &e) { 127 | fprintf(stderr, "%s: Unable to connect to pid: %s\n", 128 | argv[0], e.what()); 129 | } catch(const std::exception &e) { 130 | fprintf(stderr, "%s: Error: %s\n", argv[0], e.what()); 131 | } catch(...) { 132 | fprintf(stderr, "%s: An error occured\n", argv[0]); 133 | throw; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /shellcode-retty-linux-ia32.S: -------------------------------------------------------------------------------- 1 | #if defined(__linux__) && defined(__i386) 2 | /** injcode/shellcode-retty-linux-ia32.S 3 | * 4 | * Copyright(c) Thomas Habets 2009 5 | */ 6 | 7 | #include "asm-constants.h" 8 | /* data map */ 9 | .equ teststr, 0 /* 10 */ 10 | .equ socketstruct, 12 /* 12 */ 11 | .equ connectstruct, 24 /* 12 + 110 */ 12 | .equ recvstruct, 144 /* 12 */ 13 | .equ msghdr, 160 /* 28 */ 14 | .equ iovec, 188 /* 8 */ 15 | .equ cmsg, 196 /* 24 */ 16 | .equ scratchdata, 220 /* 4 */ 17 | .equ childfunc, 224 /* 4 */ 18 | .equ childpid, 228 /* 4 */ 19 | .equ oldtio, 232 /* 60 */ 20 | 21 | /* variables (can be inside structs) */ 22 | .equ socketfd, 24 /* permanent location of fd */ 23 | .equ fd0, 208 /* 4 */ 24 | .equ fd1, 212 /* 4 */ 25 | .equ fd2, 216 /* 4 */ 26 | 27 | .text 28 | 29 | .globl shellcodeRetty 30 | shellcodeRetty: 31 | 32 | # Debug print 33 | #movl $SYS_write, %eax 34 | #movl $2, %ebx # stderr 35 | #leal teststr(%ebp), %ecx 36 | #movl $10, %edx # len 37 | #int $0x80 38 | #movl $10, %ebx # step 10 - debug print 39 | #cmpl $0, %eax 40 | #jl errout 41 | 42 | # ioctl(0, TCGETS, &oldtio) 43 | movl $SYS_ioctl, %eax 44 | movl $0, %ebx 45 | movl $TCGETS, %ecx 46 | leal oldtio(%ebp), %edx 47 | int $0x80 48 | movl $12, %ebx # step 12 49 | cmpl $0, %eax 50 | jl errout 51 | 52 | # fork() 53 | movl $SYS_fork, %eax 54 | int $0x80 55 | cmpl $0, %eax 56 | jne parent 57 | jl errout 58 | movl childfunc(%ebp), %eax 59 | jmp *%eax 60 | parent: 61 | movl %eax, childpid(%ebp) 62 | 63 | # setpgid() 64 | setpgid: 65 | movl %eax, %ecx 66 | movl $SYS_setpgid, %eax 67 | movl $0, %ebx 68 | int $0x80 69 | movl $15, %ebx # step 15 70 | cmpl $0, %eax 71 | jl setpgid 72 | 73 | # setsid() 74 | movl $SYS_setsid, %eax 75 | int $0x80 76 | movl $73, %ebx # step 73 77 | cmpl $0, %eax 78 | jl erroutclose 79 | 80 | # kill() 81 | movl $SYS_kill, %eax 82 | movl childpid(%ebp), %ebx 83 | movl $SIGKILL, %ecx 84 | int $0x80 85 | 86 | # waitpid() 87 | movl $SYS_waitpid, %eax 88 | movl childpid(%ebp), %ebx 89 | movl $0, %ecx 90 | movl $0, %edx 91 | int $0x80 92 | 93 | # FIXME: do three open(/dev/null)s, just in case 94 | 95 | # socket() 96 | movl $SYS_socketcall, %eax 97 | movl $SC_socket, %ebx 98 | leal socketstruct(%ebp), %ecx # socket struct 99 | int $0x80 100 | movl %eax, socketfd(%ebp) 101 | movl $20, %ebx # step 20 - socket 102 | cmpl $0, %eax 103 | jl errout 104 | # FIXME: error handling 105 | 106 | # connect() 107 | movl $SYS_socketcall, %eax 108 | movl $SC_connect, %ebx 109 | leal connectstruct(%ebp), %ecx 110 | int $0x80 111 | movl $30, %ebx # step 30 - connect 112 | cmpl $0, %eax 113 | jl erroutclose 114 | 115 | # recvmsg() 116 | movl socketfd(%ebp), %eax 117 | movl %eax, recvstruct(%ebp) 118 | movl $SYS_socketcall, %eax 119 | movl $SC_recvmsg, %ebx 120 | leal recvstruct(%ebp), %ecx 121 | int $0x80 122 | movl $40, %ebx # step 40 - recvmsg 123 | cmpl $1, %eax 124 | jne errout 125 | 126 | # ioctl(fd, TIOCNOTTY, .) -- not needed. setsid() does it for us 127 | #movl $SYS_ioctl, %eax 128 | #movl $0, %ebx # fd 129 | #movl $TIOCNOTTY, %ecx 130 | #movl $0, %edx 131 | #int $0x80 132 | #movl $45, %ebx # step 45 133 | #cmpl $0, %eax 134 | #jl erroutclose 135 | 136 | # dup2(n, 0) 137 | movl $SYS_dup2, %eax 138 | movl fd0(%ebp), %ebx 139 | movl $0, %ecx 140 | int $0x80 141 | movl $50, %ebx # step 50 - dup2(n, 0) 142 | cmpl $0, %eax 143 | jl erroutclose 144 | 145 | # dup2(n, 1) 146 | movl $SYS_dup2, %eax 147 | movl fd1(%ebp), %ebx 148 | movl $1, %ecx 149 | int $0x80 150 | movl $60, %ebx # step 60 - dup2(n, 1) 151 | cmpl $0, %eax 152 | jl erroutclose 153 | 154 | # dup2(n, 2) 155 | movl $SYS_dup2, %eax 156 | movl fd2(%ebp), %ebx 157 | movl $2, %ecx 158 | int $0x80 159 | movl $70, %ebx # step 70 - dup2(n, 2) 160 | cmpl $0, %eax 161 | jl erroutclose 162 | 163 | # ioctl(fd, TIOCTTY, 1) 164 | movl $SYS_ioctl, %eax 165 | movl $0, %ebx # fd 166 | movl $TIOCSCTTY, %ecx 167 | movl $1, %edx 168 | int $0x80 169 | movl $75, %ebx # step 75 170 | cmpl $0, %eax 171 | jne erroutclose 172 | 173 | # ioctl(0, TCSETS, &oldtio) 174 | movl $SYS_ioctl, %eax 175 | movl $0, %ebx 176 | movl $TCSETS, %ecx 177 | leal oldtio(%ebp), %edx 178 | int $0x80 179 | movl $77, %ebx # step 77 180 | cmpl $0, %eax 181 | jl errout 182 | 183 | # kill() 184 | movl $SYS_kill, %eax 185 | movl $0, %ebx 186 | movl $SIGWINCH, %ecx 187 | int $0x80 188 | 189 | # close(socket) 190 | movl $SYS_close, %eax 191 | movl socketfd(%ebp), %ebx 192 | int $0x80 193 | movl $80, %ebx # step 80 194 | cmpl $0, %eax 195 | jl erroutclose 196 | 197 | # close(fd0) 198 | movl $SYS_close, %eax 199 | movl fd0(%ebp), %ebx 200 | int $0x80 201 | movl $90, %ebx # step 90 202 | cmpl $0, %eax 203 | jl erroutclose 204 | 205 | # close(fd1) 206 | movl $SYS_close, %eax 207 | movl fd1(%ebp), %ebx 208 | int $0x80 209 | movl $100, %ebx # step 100 210 | cmpl $0, %eax 211 | jl erroutclose 212 | 213 | # close(fd2) 214 | movl $SYS_close, %eax 215 | movl fd2(%ebp), %ebx 216 | int $0x80 217 | movl $110, %ebx # step 110 218 | cmpl $0, %eax 219 | jl erroutclose 220 | 221 | movl $255, %ebx 222 | # all done 223 | jmp okout 224 | 225 | .globl shellcodeRettyChild 226 | shellcodeRettyChild: 227 | # setpgid() 228 | movl $SYS_setpgid, %eax 229 | movl $0, %ebx 230 | movl $0, %ecx 231 | int $0x80 232 | 233 | # FIXME sleep(10) 234 | jmp shellcodeRettyChild 235 | # exit(0) 236 | 237 | erroutclose: 238 | #FIXME: close socket 239 | errout: 240 | okout: 241 | .globl shellcodeRettyEnd 242 | shellcodeRettyEnd: nop 243 | 244 | #endif 245 | -------------------------------------------------------------------------------- /inject.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #include "inject.h" 10 | 11 | #ifndef WIFCONTINUED 12 | #define WIFCONTINUED(a) 0 13 | #endif 14 | 15 | Inject::Inject(pid_t pid, int verbose, const char *argv0) 16 | :pid(pid),attached(false),verbose(verbose),argv0(argv0) 17 | { 18 | } 19 | 20 | 21 | Inject::~Inject() 22 | { 23 | try { 24 | detach(); 25 | } catch(...) { 26 | // FIXME: the code should handle this better than just 27 | // ignoring failure 28 | } 29 | } 30 | 31 | 32 | void 33 | Inject::detach() 34 | { 35 | uninject(); 36 | if (attached) { 37 | if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) { 38 | throw ErrSysPtrace("Inject::detach", 39 | PTRACE_DETACH, 40 | ""); 41 | } 42 | attached = false; 43 | } 44 | } 45 | void 46 | Inject::attach() 47 | { 48 | if (!attached) { 49 | attached = true; 50 | if (ptrace(PTRACE_ATTACH, pid, NULL, NULL)) { 51 | attached = false; 52 | throw ErrSysPtrace("Inject::attach", 53 | PTRACE_ATTACH, 54 | "attach"); 55 | } 56 | 57 | pagesize = 4096; // FIXME: find this 58 | 59 | // FIXME: needed? 60 | if (0 > kill(pid, SIGCONT)) { 61 | throw ErrSys("Inject::attach", "kill"); 62 | } 63 | 64 | if (0 > waitpid(pid, NULL, 0)) { 65 | throw ErrSys("Inject::attach", "waitpid"); 66 | } 67 | 68 | if (ptrace(PTRACE_GETREGS, pid, NULL, &oldregs)) { 69 | throw ErrSysPtrace("Inject::attach", 70 | PTRACE_GETREGS, 71 | "getregs"); 72 | } 73 | olddatapage.resize(pagesize); 74 | oldcodepage.resize(pagesize); 75 | peek(&olddatapage[0], dataBase(), pagesize); 76 | peek(&oldcodepage[0], codeBase(), pagesize); 77 | } 78 | } 79 | 80 | 81 | void 82 | Inject::peekpoke(const char *data, unsigned long addr, size_t len, bool poke) 83 | { 84 | unsigned long them; 85 | const char *us; 86 | 87 | us = data; 88 | them = addr; 89 | 90 | for(; 91 | len >= wordSize(); 92 | len -= wordSize(), them += wordSize(), us += wordSize()) { 93 | if (poke) { 94 | if (ptrace(PTRACE_POKEDATA, 95 | pid, 96 | them, 97 | *(ptr_t*)us)) { 98 | throw ErrSysPtrace("Inject::peekpoke", 99 | PTRACE_POKEDATA, 100 | ""); 101 | } 102 | } else { 103 | *(ptr_t*)us = ptrace(PTRACE_PEEKDATA, 104 | pid, 105 | them, 106 | NULL); 107 | } 108 | } 109 | // FIXME: handle non word-aligned peekpokes 110 | } 111 | 112 | Inject::ptr_t 113 | Inject::codeBase() 114 | { 115 | attach(); 116 | return oldregs.eip & ~(pagesize-1); 117 | } 118 | 119 | Inject::ptr_t 120 | Inject::dataBase() 121 | { 122 | attach(); 123 | return oldregs.esp & ~(pagesize-1); 124 | } 125 | 126 | 127 | /** 128 | * FIXME: error handling 129 | */ 130 | void 131 | Inject::inject(void *code, void *data) 132 | { 133 | //printf("Injecting...\n"); 134 | uninject(); 135 | 136 | injected = true; 137 | poke((char*)code, codeBase(), pageSize()); 138 | poke((char*)data, dataBase(), pageSize()); 139 | 140 | struct user_regs_struct newregs; 141 | if (ptrace(PTRACE_GETREGS, pid, NULL, &newregs)) { 142 | throw ErrSysPtrace("Inject::inject", 143 | PTRACE_GETREGS, 144 | ""); 145 | } 146 | newregs.eip = codeBase(); 147 | newregs.eax = codeBase(); 148 | newregs.ebp = dataBase(); 149 | newregs.esp = dataBase() + pageSize() - wordSize(); 150 | 151 | if (ptrace(PTRACE_SETREGS, pid, NULL, &newregs)) { 152 | throw ErrSysPtrace("Inject::inject", 153 | PTRACE_SETREGS, 154 | "Setting new registers"); 155 | } 156 | 157 | } 158 | 159 | 160 | void 161 | Inject::run() 162 | { 163 | if (!injected) { 164 | throw ErrBase("Inject::run", "not injected yet"); 165 | } 166 | 167 | time_t last = 0; 168 | struct user_regs_struct regs; 169 | do { 170 | if (ptrace(PTRACE_CONT, pid, NULL, NULL)) { 171 | perror("PTRACE_CONT"); 172 | } 173 | int status; 174 | waitpid(pid, &status, 0); 175 | if (verbose && last != time(0)) { 176 | last = time(0); 177 | printf("waitpid status: %d %d %d %d\n", 178 | WIFEXITED(status), 179 | WIFSIGNALED(status), 180 | WIFSTOPPED(status), 181 | WIFCONTINUED(status)); 182 | if (WIFSTOPPED(status)) { 183 | // FIXME: save signal and deliver later 184 | printf("Stopping signal: %d\n", 185 | WSTOPSIG(status)); 186 | } 187 | 188 | if (ptrace(PTRACE_GETREGS, pid, NULL, 189 | ®s)) { 190 | perror("getregs"); 191 | } 192 | //dumpregs(&newregs); 193 | if (0) { 194 | printf("%lx .. %p .. %lx\n", 195 | codeBase(), 196 | (void*)regs.eip, 197 | codeBase() + pageSize()); 198 | } 199 | } 200 | 201 | if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) { 202 | perror("getregs"); 203 | } 204 | } while(regs.eip != (long)(codeBase() + pageSize())); 205 | if (regs.eax) { 206 | printf("Shellcode returned non-null: %ld\n", regs.eax); 207 | dumpregs(); 208 | } 209 | } 210 | 211 | void 212 | Inject::uninject() 213 | { 214 | if (injected) { 215 | //printf("UnInjecting...\n"); 216 | poke(&olddatapage[0], dataBase(), pageSize()); 217 | poke(&oldcodepage[0], codeBase(), pageSize()); 218 | if (ptrace(PTRACE_SETREGS, pid, NULL, &oldregs)) { 219 | throw ErrSysPtrace("Inject::uninject", 220 | PTRACE_SETREGS, 221 | "Resetting original registers"); 222 | } 223 | injected = false; 224 | } 225 | } 226 | 227 | void 228 | Inject::dumpregs(bool onlyIfEAX) 229 | { 230 | struct user_regs_struct regs; 231 | if (ptrace(PTRACE_GETREGS, pid, NULL, ®s)) { 232 | perror("getregs"); 233 | } 234 | if (onlyIfEAX && !regs.eax) { 235 | return; 236 | } 237 | printf("----------------------------\n"); 238 | printf("%%eip : 0x%.8lx\n", regs.eip); 239 | printf("%%eax : 0x%.8lx %ld %s\n", regs.eax, regs.eax, 240 | strerror(-regs.eax)); 241 | printf("%%ebx : 0x%.8lx %ld\n", regs.ebx, regs.ebx); 242 | printf("%%ecx : 0x%.8lx\n", regs.ecx); 243 | printf("%%edx : 0x%.8lx\n", regs.edx); 244 | printf("%%esi : 0x%.8lx\n", regs.esi); 245 | printf("%%edi : 0x%.8lx\n", regs.edi); 246 | printf("%%ebp : 0x%.8lx\n", regs.ebp); 247 | printf("%%orig_eax : 0x%.8lx\n", regs.orig_eax); 248 | printf("%%esp : 0x%.8lx\n", regs.esp); 249 | } 250 | -------------------------------------------------------------------------------- /retty.cc: -------------------------------------------------------------------------------- 1 | // injcode/retty.cc 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include /* for openpty and forkpty */ 8 | #include /* for login_tty */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "inject.h" 15 | #include "ErrHandling.h" 16 | #include "injcode.h" 17 | 18 | //#define UNUSED(x) x __attribute__ ((unused)) 19 | #define UNUSED(x) x 20 | 21 | extern "C" char* shellcodeRetty(); 22 | extern "C" char* shellcodeRettyEnd(); 23 | extern "C" char* shellcodeRettyChild(); 24 | 25 | extern options_t options; 26 | 27 | static int proxyfdm, proxyfds; 28 | static pid_t childpid; 29 | 30 | void 31 | Retty::sigwinch(UNUSED(int x)) 32 | { 33 | struct winsize ws; 34 | if (0 > ioctl(0, TIOCGWINSZ, &ws)) { 35 | throw ErrHandling::ErrSys("Retty::sigwinch", 36 | "ioctl", 37 | "TIOCGWINSZ"); 38 | fprintf(stderr, "%s: ioctl(0, TIOCGWINSZ, ...): %s\n", 39 | options.argv0, strerror(errno)); 40 | } 41 | if (0 > ioctl(proxyfdm, TIOCSWINSZ, &ws)) { 42 | throw ErrHandling::ErrSys("Retty::sigwinch", 43 | "ioctl", 44 | "TIOCSWINSZ"); 45 | fprintf(stderr, "%s: ioctl(0, TIOCSWINSZ, ...): %s\n", 46 | options.argv0, strerror(errno)); 47 | } 48 | } 49 | 50 | int 51 | Retty::send_fds(int sd, int proxyfd) 52 | { 53 | int fds[3] = { proxyfd, 54 | proxyfd, 55 | proxyfd }; 56 | char buf[CMSG_SPACE(sizeof fds)]; 57 | 58 | struct msghdr msg; 59 | memset(&msg,0,sizeof(msg)); 60 | msg.msg_control = buf; 61 | msg.msg_controllen = sizeof(buf); 62 | 63 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 64 | cmsg->cmsg_level = SOL_SOCKET; 65 | cmsg->cmsg_type = SCM_RIGHTS; 66 | cmsg->cmsg_len = CMSG_LEN(sizeof(fds)); 67 | msg.msg_controllen = cmsg->cmsg_len; 68 | 69 | memcpy(CMSG_DATA(cmsg), fds, sizeof(fds)); 70 | 71 | char ping = 23; 72 | struct iovec ping_vec; 73 | ping_vec.iov_base = &ping; 74 | ping_vec.iov_len = sizeof(ping); 75 | 76 | msg.msg_iov = &ping_vec; 77 | msg.msg_iovlen = 1; 78 | 79 | if (0 > sendmsg(sd, &msg, 0)) { 80 | fprintf(stderr, "RettyChild> sendmsg(%d, %p) %s\n", 81 | sd, &msg, strerror(errno)); 82 | } 83 | return 0; 84 | } 85 | 86 | void 87 | Retty::child(int proxyfd) 88 | { 89 | int server_socket = socket(PF_UNIX, SOCK_STREAM, 0); 90 | 91 | struct sockaddr_un server_address = { AF_UNIX, 92 | "\0init_console" }; 93 | if (bind(server_socket, (struct sockaddr *) &server_address, 94 | sizeof server_address)) { 95 | fprintf(stderr, "RettyChild> bind() error %s\n", 96 | strerror(errno)); 97 | } 98 | if (listen(server_socket, 1)) { 99 | fprintf(stderr, "RettyChild> listen() error %s\n", 100 | strerror(errno)); 101 | } 102 | 103 | struct sockaddr_un client_address; 104 | socklen_t client_address_length = sizeof client_address; 105 | if (options.verbose) { 106 | printf("RettyChild> waiting for inject code to connect...\n"); 107 | } 108 | int cli = accept(server_socket, 109 | (struct sockaddr*)&client_address, 110 | &client_address_length); 111 | if (0 > cli) { 112 | fprintf(stderr, "RettyChild> accept() error %s\n", 113 | strerror(errno)); 114 | } 115 | close(server_socket); 116 | if (options.verbose) { 117 | printf("RettyChild> connected, sending...\n"); 118 | } 119 | send_fds(cli, proxyfd); 120 | if (options.verbose) { 121 | printf("RettyChild> all done\n"); 122 | } 123 | //sleep(3); 124 | exit(0); 125 | } 126 | 127 | std::string 128 | Retty::readFd(int fd) 129 | { 130 | char buf[128]; 131 | ssize_t n; 132 | 133 | n = read(fd, buf, sizeof(buf)); 134 | if (!n) { 135 | return ""; 136 | } 137 | if (0 > n) { 138 | perror("read"); 139 | return ""; 140 | } 141 | return std::string(buf, &buf[n]); 142 | } 143 | 144 | void 145 | Retty::setRawTerminal(int fd) 146 | { 147 | struct termios tio; 148 | if (tcgetattr(fd, &tio)) { 149 | fprintf(stderr, "%s: tcgetattr(): %s\n", options.argv0, 150 | strerror(errno)); 151 | return; 152 | } 153 | cfmakeraw(&tio); 154 | if (tcsetattr(fd, TCSANOW, &tio)) { 155 | fprintf(stderr, "%s: tcsetattr(): %s\n", options.argv0, 156 | strerror(errno)); 157 | } 158 | } 159 | 160 | 161 | void 162 | Retty::setupPty() 163 | { 164 | struct winsize ws; 165 | if (0 > tcgetattr(0, &orig_tio)) { 166 | throw ErrHandling::ErrSys("retty::setupPty", 167 | "tcgetattr", 168 | ""); 169 | } 170 | if (0 > ioctl(0, TIOCGWINSZ, &ws)) { 171 | throw ErrHandling::ErrSys("retty::setupPty", 172 | "ioctl", 173 | "TIOCGWINSZ"); 174 | } 175 | 176 | if (0 > openpty(&proxyfdm, &proxyfds, NULL, &orig_tio, &ws)) { 177 | throw ErrHandling::ErrSys("retty::setupPty", 178 | "openpty", 179 | ""); 180 | } 181 | childpid = fork(); 182 | if (!childpid) { 183 | close(proxyfdm); 184 | child(proxyfds); 185 | exit(0); 186 | } 187 | close(proxyfds); 188 | signal(SIGWINCH, sigwinch); 189 | 190 | // FIXME: communicate with child so we know when it's ready. 191 | // don't just sleep() arbitrarily. 192 | sleep(1); 193 | } 194 | 195 | Retty::~Retty() 196 | { 197 | if (0 > tcsetattr(0, TCSANOW, &orig_tio)) { 198 | fprintf(stderr, "%s: tcsetattr(0, ...)", options.argv0); 199 | } 200 | } 201 | 202 | Retty::Retty(Inject &injector) 203 | :InjMod(injector) 204 | { 205 | // save for later. Will use this to reset right before exiting 206 | if (0 > tcgetattr(0, &orig_tio)) { 207 | throw ErrSys("Retty::Retty()", 208 | "tcgetattr(0, ...)"); 209 | } 210 | 211 | setupPty(); 212 | 213 | // background it 214 | kill(options.targetpid, SIGSTOP); 215 | kill(options.targetpid, SIGCONT); 216 | 217 | char data[injector.pageSize()]; 218 | char code[injector.pageSize()]; 219 | 220 | memset(code, 0x90, injector.pageSize()); 221 | memset(data, 0, injector.pageSize()); 222 | code[injector.pageSize()-1] = 0xcc; 223 | 224 | // test string 10B @ 0 225 | strcpy(data, "Inject OK\n"); 226 | // socket() struct 12B @ 12 227 | { 228 | if (options.verbose > 1) { 229 | printf("Setting up socket struct (size 12) at 12\n"); 230 | } 231 | 232 | int socketcall_socket[] = {AF_UNIX, SOCK_STREAM, 0}; 233 | memcpy(&data[12], 234 | &socketcall_socket, 235 | sizeof(socketcall_socket)); 236 | } 237 | 238 | // connect() struct (12 + 110)B @ 24 239 | { 240 | if (options.verbose > 1) { 241 | printf("Setting up connect struct (size 12) at 24\n"); 242 | } 243 | int socketcall_connect[] = { 0, // to be filled in 244 | injector.dataBase() + 36, 245 | sizeof(struct sockaddr_un) }; 246 | memcpy(&data[24], 247 | &socketcall_connect, 248 | sizeof(socketcall_connect)); 249 | 250 | if (options.verbose > 1) { 251 | printf("Setting up connect sockaddr (size %d) at 36\n", 252 | sizeof(struct sockaddr_un)); 253 | } 254 | // FIXME: name of socket 255 | struct sockaddr_un su = { AF_UNIX, "\0init_console" }; 256 | memcpy(&data[36], 257 | &su, 258 | sizeof(su)); 259 | } 260 | 261 | // recvmsg() struct @ 144 262 | { 263 | int socketcall_recvmsg[] = { 0, // to be filled in 264 | injector.dataBase() + 160, // msg 265 | 0 }; 266 | memcpy(&data[144], 267 | &socketcall_recvmsg, 268 | sizeof(socketcall_recvmsg)); 269 | 270 | int data_msg[] = { 0,0, // name 271 | injector.dataBase() + 188, 1, // iov 272 | injector.dataBase() + 196, 24, // control 273 | 0, // flags 274 | }; 275 | memcpy(&data[160], 276 | &data_msg, 277 | sizeof(data_msg)); 278 | 279 | int data_iovec[] = { injector.dataBase() + 220, 1}; 280 | memcpy(&data[188], 281 | &data_iovec, 282 | sizeof(data_iovec)); 283 | } 284 | 285 | // symbols 286 | { 287 | *(Inject::ptr_t*)&data[224] = injector.codeBase() 288 | + ((Inject::ptr_t)shellcodeRettyChild 289 | -(Inject::ptr_t)shellcodeRetty); 290 | } 291 | 292 | size_t s = (Inject::ptr_t)shellcodeRettyEnd 293 | - (Inject::ptr_t)shellcodeRetty; 294 | if (options.verbose) { 295 | printf("Shellcode size is %d\n", s); 296 | } 297 | memcpy(code, (char*)shellcodeRetty, s); 298 | 299 | injector.inject(code, data); 300 | } 301 | 302 | void 303 | Retty::run() 304 | { 305 | setRawTerminal(0); 306 | std::string to0, to1, to2; 307 | bool todie = false; 308 | while (!todie || !to1.empty() || !to2.empty()) { 309 | struct pollfd fds[3]; 310 | int nfds; 311 | 312 | 313 | fds[0].fd = proxyfdm; 314 | fds[0].events = POLLIN; 315 | fds[0].revents = 0; 316 | fds[1].fd = 0; 317 | fds[1].events = POLLIN; 318 | fds[1].revents = 0; 319 | fds[2].fd = 1; 320 | fds[2].events = POLLIN; 321 | fds[2].revents = 0; 322 | 323 | if (!to0.empty()) { 324 | fds[0].events |= POLLOUT; 325 | } 326 | if (!to1.empty()) { 327 | fds[1].events |= POLLOUT; 328 | } 329 | if (!to2.empty()) { 330 | fds[2].events |= POLLOUT; 331 | } 332 | 333 | nfds = poll(fds, 3, -1); 334 | 335 | if (fds[0].revents & POLLHUP) { 336 | // process died/detached from terminal 337 | //close(proxyfdm); 338 | //proxyfdm = -1; 339 | todie = true; 340 | break; 341 | } 342 | 343 | if (fds[0].revents & POLLIN) { 344 | //printf("Write from 0 to 2\n"); 345 | to2 += readFd(fds[0].fd); 346 | } 347 | if ((fds[1].revents & POLLIN)) { 348 | //printf("Write from 1 to 0\n"); 349 | to0 += readFd(fds[1].fd); 350 | } 351 | if (!to0.empty() && (fds[0].revents & POLLOUT)) { 352 | write(fds[0].fd, to0.data(), to0.size()); 353 | to0 = ""; 354 | } 355 | if (!to1.empty() && (fds[1].revents & POLLOUT)) { 356 | write(fds[1].fd, to1.data(), to1.size()); 357 | to1 = ""; 358 | } 359 | if (!to2.empty() && (fds[2].revents & POLLOUT)) { 360 | write(fds[2].fd, to2.data(), to2.size()); 361 | to2 = ""; 362 | } 363 | 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------