├── CREDITS ├── LICENSE ├── Makefile ├── README ├── adbiclient ├── adbi │ ├── __init__.py │ ├── adbi.py │ ├── packet.py │ └── rsock.py ├── adbi3 └── powercmd │ ├── __init__.py │ ├── cmd.py │ └── output.py ├── adbilog ├── Makefile └── adbilog.c ├── adbiserver.c ├── arch ├── arm │ ├── disassemble.c │ ├── fncall.c │ ├── include │ │ ├── arch.h │ │ └── template_field.h │ ├── match.h │ ├── opcodes.c │ ├── patch.c │ ├── state.c │ ├── template.c │ ├── template_select.c │ ├── template_select_arm.c │ ├── template_select_thumb.c │ ├── template_select_thumb32.c │ ├── templates │ │ ├── Makefile │ │ ├── adr_t1.S │ │ ├── adr_t2.S │ │ ├── adr_t3.S │ │ ├── arm_dp_rd_rm.S │ │ ├── arm_dp_rd_rn.S │ │ ├── arm_dp_rd_rn_rm.S │ │ ├── arm_dp_rm.S │ │ ├── arm_dp_rm2.S │ │ ├── arm_dp_rn.S │ │ ├── arm_dp_rn2.S │ │ ├── arm_dp_rn_rm.S │ │ ├── arm_dp_rn_rm2.S │ │ ├── arm_generic.S │ │ ├── arm_handler.h │ │ ├── b_a1.S │ │ ├── b_t1.S │ │ ├── b_t2.S │ │ ├── b_t3.S │ │ ├── b_t4.S │ │ ├── bl_imm_a1.S │ │ ├── bl_t1.S │ │ ├── blx_imm_a2.S │ │ ├── blx_reg_a1.S │ │ ├── blx_reg_t1.S │ │ ├── blx_t2.S │ │ ├── cbz_t1.S │ │ ├── ldr_lit_t1.S │ │ ├── ldr_lit_t2.S │ │ ├── t2c │ │ ├── thumb2_generic.S │ │ ├── thumb_generic.S │ │ ├── thumb_handler.h │ │ └── thumb_nop.S │ ├── tests │ │ ├── Makefile │ │ ├── adr_t1.py │ │ ├── adr_t2.py │ │ ├── adr_t3.py │ │ ├── arm_dp_imm.py │ │ ├── arm_dp_reg.py │ │ ├── b_a1.py │ │ ├── b_t1.py │ │ ├── b_t2.py │ │ ├── b_t3.py │ │ ├── b_t4.py │ │ ├── bl_imm_a1.py │ │ ├── bl_t1.py │ │ ├── bl_t2.py │ │ ├── blx_imm_a2.py │ │ ├── blx_reg_a1.py │ │ ├── blx_reg_t1.py │ │ ├── branch.py │ │ ├── cbz_t1.py │ │ ├── ldr_lit_a1.py │ │ ├── ldr_lit_t1.py │ │ ├── ldr_lit_t2.py │ │ ├── literal.py │ │ ├── makemain │ │ ├── maketest │ │ └── test.py │ └── trap.c └── arm64 │ ├── disassemble.c │ ├── fncall.c │ ├── include │ ├── arch.h │ └── template_field.h │ ├── match.h │ ├── patch.c │ ├── state.c │ ├── template.c │ ├── template_select.c │ ├── templates │ ├── Makefile │ ├── a64_adrp.S │ ├── a64_b.S │ ├── a64_b_cond.S │ ├── a64_bl.S │ ├── a64_blr.S │ ├── a64_blr_x30.S │ ├── a64_br.S │ ├── a64_cbnz.S │ ├── a64_generic.S │ ├── a64_handler.h │ ├── a64_ldr_literal.S │ ├── a64_ldrsw_literal.S │ ├── a64_tbnz.S │ └── t2c │ ├── tests │ ├── Makefile │ ├── a64_adrp.py │ ├── a64_b.py │ ├── a64_b_cond.py │ ├── a64_bl.py │ ├── a64_blr.py │ ├── a64_br.py │ ├── a64_cbnz.py │ ├── a64_ldr_literal.py │ ├── a64_ldrsw_literal.py │ ├── a64_tbnz.py │ ├── common.py │ ├── mkmain │ └── mktest │ └── trap.c ├── communication ├── communication.c ├── communication.h ├── payload.c ├── payload.h ├── protocol.c └── protocol.h ├── configuration ├── state.c └── state.h ├── demo ├── adbi_snprintf │ ├── README │ └── adbi_snprintf.c ├── binder │ ├── README │ └── binder.patterns ├── fibo │ ├── README │ ├── fibo.adbi │ └── fibo.c ├── libc │ ├── README │ └── patterns └── openfiles │ ├── README │ └── openfiles.adbi ├── doc ├── ADBI - Documentation.html ├── ARM_TEMPLATES ├── BUILDING ├── CALLS ├── DYNAMIC_LINKER ├── EXEC_RESTOP ├── INJECTABLE ├── MKINJ ├── STABILIZATION └── TODO ├── idk ├── adbicache ├── adbipp ├── autoadbi ├── autohandler ├── cachebuilder │ ├── __init__.py │ ├── cfi.py │ ├── datatype.py │ ├── debuginfo.py │ ├── dwarftools.py │ ├── functions.py │ ├── insnset.py │ ├── lines.py │ ├── location.py │ ├── schema.sql │ ├── sections.py │ ├── symbols.py │ └── variables.py ├── cachereader │ ├── C.py │ ├── __init__.py │ ├── addr2line.py │ ├── base.py │ ├── cfa.py │ ├── datatype │ │ ├── __init__.py │ │ ├── builtin.py │ │ ├── compound.py │ │ ├── create.py │ │ ├── datatype.py │ │ ├── enum.py │ │ ├── indirect.py │ │ └── typedef.py │ ├── debuginfo.py │ ├── files.py │ ├── framepointers.py │ ├── function.py │ ├── insnset.py │ ├── lines.py │ ├── location.py │ ├── symbols.py │ ├── types.py │ └── variables.py ├── common │ ├── __init__.py │ ├── deco.py │ ├── enums.py │ ├── leb128.py │ ├── mixin.py │ └── output.py ├── dwexpr │ ├── LICENCE.txt │ ├── __init__.py │ ├── constants.py │ ├── machine.py │ └── result.py ├── include │ ├── adbicpy.h │ ├── common.h │ ├── division.h │ ├── errno.h │ ├── futex.h │ ├── gcc.h │ ├── handler.h │ ├── inj.h │ ├── io.h │ ├── mmap.h │ ├── mutex.h │ ├── net.h │ ├── personality.h │ ├── syscall_template.h │ ├── syscalls.h │ ├── time.h │ ├── types.h │ ├── unix.h │ └── varargs.h ├── inj ├── inject.x ├── libasdd │ ├── __init__.py │ ├── disarm.py │ └── libasdd.so ├── mkinj ├── readinj ├── tests │ ├── Makefile │ ├── args.c │ ├── assembly.S │ ├── basetypes.c │ ├── fibo.c │ ├── functions.c │ ├── tls.c │ ├── types.c │ └── vars.c └── toarray ├── inj ├── adbi │ ├── Makefile │ ├── adbi.c │ └── print.c ├── adbi_mmap │ ├── Makefile │ └── adbi_mmap.c ├── adbi_munmap │ ├── Makefile │ └── adbi_munmap.c └── dummy │ ├── Makefile │ └── dummy.c ├── injectable ├── injectable.c ├── injectable.h ├── injfile.c └── injfile.h ├── injection ├── fncall.h ├── inject.h ├── injection.c └── injection.h ├── lib ├── asdd │ ├── include │ │ ├── disarm.h │ │ ├── likely.h │ │ ├── logger.h │ │ ├── stringbuf.h │ │ └── tree.h │ ├── libasdd.a │ └── libasdd64.a └── capstone │ ├── LICENSE.TXT │ ├── include │ ├── arm.h │ ├── arm64.h │ ├── capstone.h │ ├── mips.h │ ├── platform.h │ ├── ppc.h │ ├── sparc.h │ ├── systemz.h │ ├── x86.h │ └── xcore.h │ └── libcapstone.a ├── make_deb.sh ├── make_toolchain_deb.sh ├── process ├── linker.c ├── linker.h ├── list.c ├── list.h ├── process.c ├── process.h ├── segment.c ├── segment.h ├── spawn.c ├── spawn.h ├── thread.c └── thread.h ├── procutil ├── elf.c ├── elf.h ├── mem.c ├── mem.h ├── procfs.c ├── procfs.h ├── procfs_maps.c ├── ptrace.c ├── ptrace.h ├── tgkill.c ├── tgkill.h ├── wait.c └── wait.h ├── tracepoint ├── jump.c ├── jump.h ├── patch.h ├── template.c ├── template.h ├── tracepoint.c └── tracepoint.h ├── unused-syms └── util ├── bindata.h ├── bitops.h ├── capabilities.c ├── capabilities.h ├── common.c ├── common.h ├── human.c ├── human.h ├── signal.c └── signal.h /CREDITS: -------------------------------------------------------------------------------- 1 | Engineers responsible for this project were: 2 | 3 | * Michal Lesniewski (m.lesniewski@samsung.com) 4 | Main ADBI developer. Developed version 1 and 2 and made heavy foundation for the current version no 3. 5 | 6 | * Jakub Janeczko (j.janeczko@samsung.com) 7 | Successive ADBI developer. Took over ADBI development after Michal's retirement from this project, evolved and concluded version 3. Finally ported ADBI for the ARM64 architecture. 8 | 9 | * Bartosz Zator (b.zator@samsung.com) 10 | Devised the ADBI idea, technically and organizationally managed the project throughout its history. 11 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Android Dynamic Binary Instrumentation (ADBI) is a tool for dynamically tracing Android native layer. Using this tool you can insert tracepoints (and a set of corresponding handlers) dynamically into the process address space of a running Android system. When the tracepoint is hit your custom handler (which can be written in C) is executed. You can deliver your own code through the handlers. It is possible to access process variables and memory. Host side tool written in Python communicates with the native adbiserver process (which resembles the gdb-server in its operation) and translates source level symbols into addresses within the final binaries. As of authors knowledge this is a first such tool for ARM (including ARM64) architecture. 2 | ADBI tool was developed in Samsung Poland R&D Center located in Warsaw, Poland as a research project for new development tools and process improvement. 3 | 4 | Sample features: 5 | Generates function trace from Android native user space 6 | Allows for dynamically driven trace configuration 7 | Can measure time between instructions for profiling 8 | Injects custom code into running process 9 | Can modify and reimplement running native applications 10 | 11 | Benefits: 12 | No recompilation of debugging application is needed 13 | Can see what exactly happens in Android native layer 14 | Finding problem areas, tracking down strange bugs more manageable 15 | Better system knowledge, faster product delivery 16 | -------------------------------------------------------------------------------- /adbiclient/adbi/__init__.py: -------------------------------------------------------------------------------- 1 | from adbi import ADBI, ADBIException -------------------------------------------------------------------------------- /adbiclient/adbi/rsock.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | class ReliableSocket(object): 4 | 5 | def __init__(self, address): 6 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 | try: 8 | self.socket.connect(address) 9 | except socket.error as e: 10 | raise IOError 11 | 12 | def send(self, data): 13 | total = 0 14 | while total < len(data): 15 | sent = self.socket.send(data[total:]) 16 | if not sent: 17 | raise IOError('Connection error.') 18 | total += sent 19 | 20 | def recv(self, length): 21 | result = '' 22 | while len(result) < length: 23 | chunk = self.socket.recv(length - len(result)) 24 | if not chunk: 25 | raise IOError('Connection error.') 26 | result += chunk 27 | return result 28 | 29 | def close(self): 30 | self.socket.close() -------------------------------------------------------------------------------- /adbiclient/powercmd/__init__.py: -------------------------------------------------------------------------------- 1 | from cmd import * 2 | import output -------------------------------------------------------------------------------- /adbilog/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS = -DNDEBUG 2 | CFLAGS = -Wall -Wextra -O3 -fPIE 3 | LDFLAGS = -pie 4 | 5 | all: adbilog 6 | 7 | adbilog: adbilog.o 8 | 9 | adbilog.o: adbilog.c 10 | 11 | clean: 12 | $(RM) adbilog adbilog.o 13 | 14 | push: adbilog 15 | adb push adbilog /data/ 16 | @echo 'pushed to /data/' 17 | 18 | run: push 19 | @echo 'launching /data/adbilog...' 20 | adb shell /data/adbilog 21 | 22 | .SILENT: 23 | .PHONY: all clean push 24 | -------------------------------------------------------------------------------- /adbiserver.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "communication/communication.h" 6 | #include "communication/protocol.h" 7 | 8 | #include "process/process.h" 9 | #include "process/thread.h" 10 | 11 | #include "procutil/wait.h" 12 | #include "injectable/injectable.h" 13 | 14 | #include "util/signal.h" 15 | #include "util/capabilities.h" 16 | 17 | #include "logger.h" 18 | 19 | static void cleanup() { 20 | debug("Cleaning up..."); 21 | process_cleanup(); 22 | comm_cleanup(); 23 | protocol_cleanup(); 24 | injectable_cleanup(); 25 | debug("Cleanup complete."); 26 | } 27 | 28 | static void init() { 29 | 30 | int initialized = protocol_init() && caps_init() && signal_init() && comm_init() && injectable_init(); 31 | 32 | if (!initialized) { 33 | fatal("Initialization failed."); 34 | cleanup(); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | } 39 | 40 | static void loop() { 41 | 42 | alarm(10); 43 | 44 | while (likely(!signal_quit)) { 45 | 46 | #if 0 47 | { 48 | /* sanity check */ 49 | void tc(thread_t * thread) { 50 | assert(thread->references == 2); 51 | } 52 | void pc(process_t * process) { 53 | assert(!tree_empty(&process->threads)); 54 | assert(process->references == 2 + tree_size(&process->threads)); 55 | thread_iter(process, tc); 56 | } 57 | process_iter(pc); 58 | } 59 | #endif 60 | 61 | signal_wait(); 62 | 63 | if (likely(signal_child)) { 64 | wait_main(); 65 | } 66 | 67 | if (unlikely(signal_io)) { 68 | comm_handle_io(); 69 | signal_io = 0; 70 | } 71 | 72 | if (unlikely(signal_disconnected)) { 73 | comm_handle_io(); 74 | } 75 | 76 | if (unlikely(signal_alarm)) { 77 | alarm(10); 78 | signal_alarm = 0; 79 | } 80 | 81 | } 82 | 83 | warning("Exiting."); 84 | } 85 | 86 | 87 | int main(/* int argc, char * argv[] */) { 88 | 89 | info("Welcome to ADBI server."); 90 | debug("Built on %s at %s.", __DATE__, __TIME__); 91 | 92 | logger_level = LOGGER_DEBUG; 93 | 94 | init(); 95 | 96 | loop(); 97 | cleanup(); 98 | 99 | return EXIT_SUCCESS; 100 | } 101 | -------------------------------------------------------------------------------- /arch/arm/include/template_field.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_FIELD_H_ 2 | #define TEMPLATE_FIELD_H_ 3 | 4 | typedef enum template_field_id_t { 5 | 6 | /* End marker */ 7 | TF_NULL = 0, 8 | 9 | /* Insert the original traced instruction opcode */ 10 | TF_INSN, 11 | 12 | /* Absolute address of the high-level handler */ 13 | TF_HANDLER_ADDRESS, 14 | 15 | /* Insert the address of the traced instruction. */ 16 | TF_ORIG_PC, 17 | 18 | /* Insert the value of the PC at the traced instruction as seen by the processor */ 19 | TF_READ_PC, 20 | 21 | /* Insert the address of the instruction following the traced instruction */ 22 | TF_NEXT_PC, 23 | 24 | 25 | /*** Instruction patching ***/ 26 | TF_PATCH_COND, 27 | 28 | TF_PATCH_RD2RD, 29 | TF_PATCH_RD2RT, 30 | TF_PATCH_RD2RM, 31 | TF_PATCH_RD2RN, 32 | 33 | TF_PATCH_RT2RD, 34 | TF_PATCH_RT2RT, 35 | TF_PATCH_RT2RM, 36 | TF_PATCH_RT2RN, 37 | 38 | TF_PATCH_RM2RD, 39 | TF_PATCH_RM2RT, 40 | TF_PATCH_RM2RM, 41 | TF_PATCH_RM2RN, 42 | 43 | TF_PATCH_RN2RD, 44 | TF_PATCH_RN2RT, 45 | TF_PATCH_RN2RM, 46 | TF_PATCH_RN2RN, 47 | 48 | TF_PATCH_RD2RS, 49 | TF_PATCH_RT2RS, 50 | TF_PATCH_RM2RS, 51 | TF_PATCH_RN2RS, 52 | 53 | /*** Helper values ***/ 54 | 55 | /* Insert the result of the Thumb ADR instruction. */ 56 | TF_ADR_T1_VAL, 57 | TF_ADR_T2_VAL, 58 | TF_ADR_T3_VAL, 59 | 60 | /* Insert load address of the Thumb load literal instruction (ldr3). */ 61 | TF_LDR_LIT_T1_ADDRESS, 62 | TF_LDR_LIT_T2_ADDRESS, 63 | 64 | /* Insert branch addresses. */ 65 | TF_B_T1_TARGET, 66 | TF_B_T2_TARGET, 67 | TF_CBZ_T1_TARGET, 68 | TF_B_T3_TARGET, 69 | TF_B_T4_TARGET, 70 | TF_BL_T1_TARGET, 71 | TF_BLX_T2_TARGET, 72 | TF_B_A1_TARGET, 73 | TF_BL_IMM_A1_TARGET, 74 | TF_BLX_IMM_A2_TARGET, 75 | 76 | } template_field_id_t; 77 | 78 | #define TF_PATCH_RD TF_PATCH_RD2RD 79 | #define TF_PATCH_RT TF_PATCH_RT2RT 80 | #define TF_PATCH_RN TF_PATCH_RN2RN 81 | #define TF_PATCH_RM TF_PATCH_RM2RM 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /arch/arm/opcodes.c: -------------------------------------------------------------------------------- 1 | #include "disarm.h" 2 | 3 | /* Disassemble the given instruction of the given kind and return a string representing the instruction. The result 4 | * string may additionally include comments and more detailed information (like exact branch destination addresses). 5 | * Warning: the returned string is a thread-local variable. */ 6 | const char * arm_disassemble_extended(insn_t insn, insn_kind_t kind, address_t pc) { 7 | 8 | switch (kind) { 9 | case INSN_KIND_THUMB: 10 | return disthumba(insn, pc); 11 | case INSN_KIND_THUMB2: 12 | return disthumb2a(insn, pc); 13 | case INSN_KIND_ARM: 14 | return disarma(insn, pc); 15 | default: 16 | adbi_bug_unrechable(); 17 | return ""; 18 | } 19 | } 20 | 21 | /* Disassemble the given instruction of the given kind and return a string representing the instruction. 22 | * Warning: the returned string is a thread-local variable. */ 23 | const char * arm_disassemble(insn_t insn, insn_kind_t kind) { 24 | char * disassembly = (char *) arm_disassemble_extended(insn, kind, 0); 25 | char * d; 26 | 27 | for (d = disassembly; *d; ++d) { 28 | if (*d == '\t') { 29 | /* replace tabs by spaces */ 30 | *d = ' '; 31 | } 32 | 33 | if (*d == ';') { 34 | /* discard comments */ 35 | *d = '\0'; 36 | break; 37 | } 38 | } 39 | 40 | /* trim spaces on the right */ 41 | for (--d; (d > disassembly) && *d == ' '; --d) *d = '\0'; 42 | 43 | return disassembly; 44 | } 45 | -------------------------------------------------------------------------------- /arch/arm/template_select.c: -------------------------------------------------------------------------------- 1 | #include "tracepoint/template.h" 2 | 3 | const template_t * template_select_arm(insn_t insn); 4 | const template_t * template_select_thumb(insn_t insn); 5 | const template_t * template_select_thumb32(insn_t insn); 6 | 7 | const template_t * template_select(insn_t insn, insn_kind_t kind) { 8 | switch (kind) { 9 | case INSN_KIND_THUMB: 10 | return template_select_thumb(insn); 11 | case INSN_KIND_THUMB2: 12 | return template_select_thumb32(insn); 13 | case INSN_KIND_ARM: 14 | return template_select_arm(insn); 15 | default: 16 | return NULL; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /arch/arm/templates/Makefile: -------------------------------------------------------------------------------- 1 | SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))$(SELF_DIR) 2 | T2C := $(SELF_DIR)/t2c 3 | 4 | SRC := $(shell find . -maxdepth 1 -name "*.S") 5 | OBJ := $(SRC:.S=.o) 6 | 7 | OUT := templates.c 8 | OUT_HEAD := $(OUT:.c=.h) 9 | 10 | CC := $(CCv7) 11 | CFLAGS += -march=armv7-a -ggdb3 -O0 12 | 13 | all: $(OUT) $(OUT_HEAD) 14 | 15 | $(OBJ): %.o : %.S 16 | @echo " [TMP] $@" 17 | @$(CC) $(CFLAGS) -c -o $@ $< 18 | 19 | $(OUT): $(OBJ) 20 | @echo " [T2C] $@" 21 | @$(T2C) -o $@ $^ 22 | 23 | $(OUT_HEAD): $(OBJ) 24 | @echo " [T2H] $@" 25 | @$(T2C) -o $@ -H $^ 26 | 27 | clean: 28 | @$(RM) $(OBJ) $(OUT) $(OUT_HEAD) 29 | 30 | .PHONY: clean 31 | 32 | 33 | -------------------------------------------------------------------------------- /arch/arm/templates/adr_t1.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_rd: 5 | /* In the following instruction, r0 will be replaced by the original instruction's destination register rd. */ 6 | ldr.n r0, tf_adr_t1_val 7 | /* Jump back. */ 8 | ldr.w pc, tf_next_pc 9 | 10 | HANDLER_CONSTANTS 11 | 12 | tf_adr_t1_val: 13 | .word BAD 14 | tf_next_pc: 15 | .word BAD 16 | 17 | HANDLER_END 18 | -------------------------------------------------------------------------------- /arch/arm/templates/adr_t2.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_rt2rd: 5 | /* In the following instruction, r0 will be replaced by the original instruction's destination register rd. */ 6 | ldr.w r0, tf_adr_t2_val 7 | /* Jump back. */ 8 | ldr.w pc, tf_next_pc 9 | 10 | HANDLER_CONSTANTS 11 | 12 | tf_adr_t2_val: 13 | .word BAD 14 | tf_next_pc: 15 | .word BAD 16 | 17 | HANDLER_END 18 | -------------------------------------------------------------------------------- /arch/arm/templates/adr_t3.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_rt2rd: 5 | /* In the following instruction, r0 will be replaced by the original instruction's destination register rd. */ 6 | ldr.w r0, tf_adr_t3_val 7 | /* Jump back. */ 8 | ldr.w pc, tf_next_pc 9 | 10 | HANDLER_CONSTANTS 11 | 12 | tf_adr_t3_val: 13 | .word BAD 14 | tf_next_pc: 15 | .word BAD 16 | 17 | HANDLER_END 18 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rd_rm.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rd == rm == pc 3 | * rn != pc 4 | */ 5 | 6 | #include "arm_handler.h" 7 | HANDLER_BEGIN 8 | 9 | tf_patch_cond: 10 | b ool_handler /* condition is true, execute instruction OOL */ 11 | ldr pc, tf_next_pc /* condition is false, return to original code */ 12 | 13 | 14 | ool_handler: 15 | 16 | sub sp, #4 /* allocate one word on the stack */ 17 | tf_patch_rt2rs1: 18 | push { r3 } /* push temporary register */ 19 | 20 | tf_patch_rt2rs2: 21 | ldr r3, tf_read_pc /* load original pc value into temporary register */ 22 | 23 | tf_insn: 24 | tf_patch_rm2rs: 25 | tf_patch_rd2rs: 26 | add r3, r0, r3 /* original instruction with rd and rm replaced by rs */ 27 | 28 | tf_patch_rt2rs3: 29 | str r3, [sp, #4] /* store result in second element on the stack */ 30 | 31 | tf_patch_rt2rs4: 32 | pop { r3 } /* pop temporary register */ 33 | pop { pc } /* pop the pc */ 34 | 35 | 36 | HANDLER_CONSTANTS 37 | 38 | tf_next_pc: 39 | .word BAD 40 | tf_read_pc: 41 | .word BAD 42 | 43 | HANDLER_END 44 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rd_rn.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rd == rn == pc 3 | * rm != pc 4 | */ 5 | 6 | #include "arm_handler.h" 7 | HANDLER_BEGIN 8 | 9 | tf_patch_cond: 10 | b ool_handler /* condition is true, execute instruction OOL */ 11 | ldr pc, tf_next_pc /* condition is false, return to original code */ 12 | 13 | 14 | ool_handler: 15 | 16 | sub sp, #4 /* allocate one word on the stack */ 17 | tf_patch_rt2rs1: 18 | push { r3 } /* push temporary register */ 19 | 20 | tf_patch_rt2rs2: 21 | ldr r3, tf_read_pc /* load original pc value into temporary register */ 22 | 23 | tf_insn: 24 | tf_patch_rn2rs: 25 | tf_patch_rd2rs: 26 | add r3, r3, r0 /* original instruction with rd and rn replaced by rs */ 27 | 28 | tf_patch_rt2rs3: 29 | str r3, [sp, #4] /* store result in second element on the stack */ 30 | 31 | tf_patch_rt2rs4: 32 | pop { r3 } /* pop temporary register */ 33 | pop { pc } /* pop the pc */ 34 | 35 | 36 | HANDLER_CONSTANTS 37 | 38 | tf_next_pc: 39 | .word BAD 40 | tf_read_pc: 41 | .word BAD 42 | 43 | HANDLER_END 44 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rd_rn_rm.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rd == rm == rn == pc 3 | */ 4 | 5 | #include "arm_handler.h" 6 | HANDLER_BEGIN 7 | 8 | tf_patch_cond: 9 | b ool_handler /* condition is true, execute instruction OOL */ 10 | ldr pc, tf_next_pc /* condition is false, return to original code */ 11 | 12 | 13 | ool_handler: 14 | 15 | sub sp, #4 /* allocate one word on the stack */ 16 | tf_patch_rt2rs1: 17 | push { r3 } /* push temporary register */ 18 | 19 | tf_patch_rt2rs2: 20 | ldr r3, tf_read_pc /* load original pc value into temporary register */ 21 | 22 | tf_insn: 23 | tf_patch_rm2rs: 24 | tf_patch_rn2rs: 25 | tf_patch_rd2rs: 26 | add r3, r3, r3 /* original instruction with rd, rn and rm replaced by rs */ 27 | 28 | tf_patch_rt2rs3: 29 | str r3, [sp, #4] /* store result in second element on the stack */ 30 | 31 | tf_patch_rt2rs4: 32 | pop { r3 } /* pop temporary register */ 33 | pop { pc } /* pop the pc */ 34 | 35 | 36 | HANDLER_CONSTANTS 37 | 38 | tf_next_pc: 39 | .word BAD 40 | tf_read_pc: 41 | .word BAD 42 | 43 | HANDLER_END 44 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rm.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rm == pc 3 | * rn != pc 4 | * rd != pc 5 | * rn != rd 6 | * 7 | * Opcodes: 8 | * cccc 00xo ooos nnnn dddd ssss ttt0 mmmm register, immediate shift 9 | */ 10 | 11 | #include "arm_handler.h" 12 | HANDLER_BEGIN 13 | 14 | tf_patch_cond: 15 | tf_patch_rd: 16 | ldr r1, tf_read_pc /* load original pc value into rd */ 17 | tf_insn: 18 | tf_patch_rm2rd: 19 | add r0, r0, r1 /* original instruction with rm changed to rd */ 20 | 21 | ldr pc, tf_next_pc /* unconditional return */ 22 | 23 | HANDLER_CONSTANTS 24 | 25 | tf_next_pc: 26 | .word BAD 27 | tf_read_pc: 28 | .word BAD 29 | 30 | HANDLER_END 31 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rm2.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rm == pc 3 | * rd != pc 4 | * rn != pc 5 | * rn == rd or rd is not used 6 | */ 7 | 8 | #include "arm_handler.h" 9 | HANDLER_BEGIN 10 | 11 | tf_patch_cond: 12 | b ool_handler /* condition is true, execute instruction OOL */ 13 | ldr pc, tf_next_pc /* condition is false, return to original code */ 14 | 15 | ool_handler: 16 | 17 | tf_patch_rt2rs1: 18 | push { r3 } /* push temporary register */ 19 | 20 | tf_patch_rt2rs2: 21 | ldr r3, tf_read_pc /* load original pc value into temporary register */ 22 | 23 | tf_insn: 24 | tf_patch_rm2rs: 25 | add r0, r0, r3 /* original instruction with rn replaced by rs */ 26 | 27 | tf_patch_rt2rs4: 28 | pop { r3 } /* pop temporary register */ 29 | 30 | ldr pc, tf_next_pc /* return to original code */ 31 | 32 | HANDLER_CONSTANTS 33 | 34 | tf_next_pc: 35 | .word BAD 36 | tf_read_pc: 37 | .word BAD 38 | 39 | HANDLER_END 40 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rn.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rn == pc 3 | * rm != pc 4 | * rd != pc 5 | * rm != rd 6 | * 7 | * Opcodes: 8 | * cccc 00xo ooos nnnn dddd rrrr iiii iiii immediate 9 | * cccc 00xo ooos nnnn dddd ssss ttt0 mmmm register, immediate shift 10 | * 11 | * This handler will also work for ldr and ldrb instructions (literal), opcodes: 12 | * cccc 010x u1x1 1111 tttt iiii iiii iiii ldrb (literal) 13 | * cccc 010x u0x1 1111 tttt iiii iiii iiii ldr (literal) 14 | */ 15 | 16 | #include "arm_handler.h" 17 | HANDLER_BEGIN 18 | 19 | tf_patch_cond: 20 | tf_patch_rd: 21 | ldr r0, tf_read_pc /* load original pc value into rd */ 22 | tf_insn: 23 | tf_patch_rn2rd: 24 | add r0, r0, #0 /* original instruction with rn changed to rd */ 25 | 26 | ldr pc, tf_next_pc /* unconditional return */ 27 | 28 | HANDLER_CONSTANTS 29 | 30 | tf_next_pc: 31 | .word BAD 32 | tf_read_pc: 33 | .word BAD 34 | 35 | HANDLER_END 36 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rn2.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rn == pc 3 | * rd != pc 4 | * rm != pc 5 | * rm == rd or rd is not used 6 | */ 7 | 8 | #include "arm_handler.h" 9 | HANDLER_BEGIN 10 | 11 | tf_patch_cond: 12 | b ool_handler /* condition is true, execute instruction OOL */ 13 | ldr pc, tf_next_pc /* condition is false, return to original code */ 14 | 15 | ool_handler: 16 | 17 | tf_patch_rt2rs1: 18 | push { r3 } /* push temporary register */ 19 | 20 | tf_patch_rt2rs2: 21 | ldr r3, tf_read_pc /* load original pc value into temporary register */ 22 | 23 | tf_insn: 24 | tf_patch_rn2rs: 25 | add r0, r3, r0 /* original instruction with rn replaced by rs */ 26 | 27 | tf_patch_rt2rs4: 28 | pop { r3 } /* pop temporary register */ 29 | 30 | ldr pc, tf_next_pc /* return to original code */ 31 | 32 | HANDLER_CONSTANTS 33 | 34 | tf_next_pc: 35 | .word BAD 36 | tf_read_pc: 37 | .word BAD 38 | 39 | HANDLER_END 40 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rn_rm.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rn == rm == pc 3 | * rd != pc 4 | * 5 | * Opcodes: 6 | * cccc 00xo ooos nnnn dddd ssss ttt0 mmmm register, immediate shift 7 | */ 8 | 9 | #include "arm_handler.h" 10 | HANDLER_BEGIN 11 | 12 | tf_patch_cond: 13 | tf_patch_rd: 14 | ldr r1, tf_read_pc /* load original pc value into rd */ 15 | 16 | tf_insn: 17 | tf_patch_rn2rd: 18 | tf_patch_rm2rd: 19 | add r0, r0, r1 /* original instruction with rn and rm changed to rd */ 20 | 21 | ldr pc, tf_next_pc /* unconditional return */ 22 | 23 | HANDLER_CONSTANTS 24 | 25 | tf_next_pc: 26 | .word BAD 27 | tf_read_pc: 28 | .word BAD 29 | 30 | HANDLER_END 31 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_dp_rn_rm2.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM data processing instructions, where: 2 | * rn == pc 3 | * rd != pc 4 | * rm != pc 5 | * rm == rd or rd is not used 6 | */ 7 | 8 | #include "arm_handler.h" 9 | HANDLER_BEGIN 10 | 11 | tf_patch_cond: 12 | b ool_handler /* condition is true, execute instruction OOL */ 13 | ldr pc, tf_next_pc /* condition is false, return to original code */ 14 | 15 | ool_handler: 16 | 17 | tf_patch_rt2rs1: 18 | push { r3 } /* push temporary register */ 19 | 20 | tf_patch_rt2rs2: 21 | ldr r3, tf_read_pc /* load original pc value into temporary register */ 22 | 23 | tf_insn: 24 | tf_patch_rn2rs: 25 | tf_patch_rm2rs: 26 | add r0, r3, r3 /* original instruction with rn and rm replaced by rs */ 27 | 28 | tf_patch_rt2rs4: 29 | pop { r3 } /* pop temporary register */ 30 | 31 | ldr pc, tf_next_pc /* return to original code */ 32 | 33 | HANDLER_CONSTANTS 34 | 35 | tf_next_pc: 36 | .word BAD 37 | tf_read_pc: 38 | .word BAD 39 | 40 | HANDLER_END 41 | -------------------------------------------------------------------------------- /arch/arm/templates/arm_generic.S: -------------------------------------------------------------------------------- 1 | #include "arm_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | tf_insn: 6 | nop 7 | ldr pc, tf_next_pc 8 | 9 | HANDLER_CONSTANTS 10 | 11 | tf_next_pc: 12 | .word BAD 13 | 14 | HANDLER_END 15 | -------------------------------------------------------------------------------- /arch/arm/templates/b_a1.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM branch instruction with an immediate operand. 2 | * 3 | * Opcode: 4 | * cccc 1010 iiii iiii iiii iiii iiii iiii B (immediate) 5 | */ 6 | 7 | #include "arm_handler.h" 8 | HANDLER_BEGIN 9 | 10 | tf_patch_cond: 11 | /* The following instruction will have the condition code of the original instruction assigned. If the 12 | * condition is true, it will cause a branch to the destination address. */ 13 | ldr pc, tf_b_a1_target 14 | /* This instruction will be executed unconditionally, it will branch to the instruction following the 15 | * original instruction. Note that it will only be executed when the condition of the first instruction 16 | * is false. */ 17 | ldr pc, tf_next_pc 18 | 19 | HANDLER_CONSTANTS 20 | 21 | tf_next_pc: 22 | .word BAD 23 | tf_b_a1_target: 24 | .word BAD 25 | 26 | HANDLER_END 27 | -------------------------------------------------------------------------------- /arch/arm/templates/b_t1.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_cond: 5 | beq.n yes 6 | no: 7 | /* Condition false. */ 8 | ldr.w pc, tf_next_pc 9 | yes: 10 | /* Condition true. */ 11 | ldr.w pc, tf_b_t1_target 12 | 13 | HANDLER_CONSTANTS 14 | 15 | tf_next_pc: 16 | .word BAD 17 | tf_b_t1_target: 18 | .word BAD 19 | 20 | HANDLER_END 21 | -------------------------------------------------------------------------------- /arch/arm/templates/b_t2.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | ldr.w pc, tf_b_t2_target 4 | 5 | HANDLER_CONSTANTS 6 | 7 | tf_b_t2_target: 8 | .word BAD 9 | 10 | HANDLER_END 11 | -------------------------------------------------------------------------------- /arch/arm/templates/b_t3.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_cond: 5 | beq.w yes 6 | no: 7 | /* Condition false. */ 8 | ldr.w pc, tf_next_pc 9 | yes: 10 | /* Condition true. */ 11 | ldr.w pc, tf_b_t3_target 12 | 13 | HANDLER_CONSTANTS 14 | 15 | tf_next_pc: 16 | .word BAD 17 | tf_b_t3_target: 18 | .word BAD 19 | 20 | HANDLER_END 21 | -------------------------------------------------------------------------------- /arch/arm/templates/b_t4.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | /* Branch. */ 4 | ldr.w pc, tf_b_t4_target 5 | 6 | HANDLER_CONSTANTS 7 | 8 | tf_b_t4_target: 9 | .word BAD 10 | 11 | HANDLER_END 12 | -------------------------------------------------------------------------------- /arch/arm/templates/bl_imm_a1.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM branch and link instruction with an immediate operand. 2 | * 3 | * Opcode: 4 | * cccc 1011 iiii iiii iiii iiii iiii iiii BL (immediate) 5 | */ 6 | 7 | #include "arm_handler.h" 8 | HANDLER_BEGIN 9 | 10 | tf_patch_cond1: 11 | ldr lr, tf_next_pc /* set the link register */ 12 | tf_patch_cond2: 13 | ldr pc, tf_bl_imm_a1_target 14 | ldr pc, tf_next_pc /* return */ 15 | 16 | HANDLER_CONSTANTS 17 | 18 | tf_next_pc: 19 | .word BAD 20 | tf_bl_imm_a1_target: 21 | .word BAD 22 | 23 | HANDLER_END 24 | -------------------------------------------------------------------------------- /arch/arm/templates/bl_t1.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | /* Set link register. */ 4 | ldr.w lr, tf_next_pc 5 | /* Branch. */ 6 | ldr.w pc, tf_bl_t1_target 7 | 8 | HANDLER_CONSTANTS 9 | 10 | tf_bl_t1_target: 11 | .word BAD 12 | tf_next_pc: 13 | .word BAD 14 | 15 | HANDLER_END 16 | -------------------------------------------------------------------------------- /arch/arm/templates/blx_imm_a2.S: -------------------------------------------------------------------------------- 1 | /* OOL handler for the ARM branch and link with exchange instruction with an immediate operand. 2 | * 3 | * Opcode: 4 | * 1111 101h iiii iiii iiii iiii iiii iiii BLX (immediate) 5 | */ 6 | 7 | #include "arm_handler.h" 8 | HANDLER_BEGIN 9 | /* The following 2 instructions will be executed unconditionally. Note that loading a value to the pc can 10 | * cause an exchange only on ARMv5 and above. */ 11 | ldr lr, tf_next_pc 12 | ldr pc, tf_blx_imm_a2_target 13 | 14 | HANDLER_CONSTANTS 15 | 16 | tf_next_pc: 17 | .word BAD 18 | tf_blx_imm_a2_target: 19 | .word BAD /* this value MUST have the last bit set to make it exchange */ 20 | 21 | HANDLER_END 22 | -------------------------------------------------------------------------------- /arch/arm/templates/blx_reg_a1.S: -------------------------------------------------------------------------------- 1 | /* 2 | OOL handler for the blx (register) instruction using encoding A1. 3 | 4 | Notes: 5 | * The handler sets the link register explicitly -- it loads the address of the next instruction in the original 6 | process segment. This approach is similar to tail recursion. However, in our case this is not only an 7 | optimization. Note that the handler could be removed from memory after the branch and before return. In this 8 | case the return address would become invalid. 9 | * The destination register can be the link register itself (i.e. blx lr). This is not as uncommon as it might 10 | seem. In some cases optimization may choose the link register as the destination register to not clobber 11 | other registers. To properly handle these cases as well, we first push the destination register onto the 12 | stack, then we set the new link register value, and then we finally pop the pushed value into the pc. 13 | */ 14 | 15 | #include "arm_handler.h" 16 | HANDLER_BEGIN 17 | 18 | tf_patch_cond1: 19 | tf_patch_rt2rm: 20 | /* conditionally push the destination register (rm) onto the stack */ 21 | push { r0 } 22 | tf_patch_cond2: 23 | /* conditionally set the link register */ 24 | ldr lr, tf_next_pc 25 | tf_patch_cond3: 26 | /* conditionally pop the destination register into pc -- this will cause the actual (interworking) branch */ 27 | pop { pc } 28 | 29 | /* this gets executed unconditionally, only when there was no branch */ 30 | ldr pc, tf_next_pc 31 | 32 | HANDLER_CONSTANTS 33 | 34 | tf_next_pc: 35 | .word BAD 36 | 37 | HANDLER_END 38 | -------------------------------------------------------------------------------- /arch/arm/templates/blx_reg_t1.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | ldr.w lr, tf_next_pc 4 | tf_patch_rm: 5 | bx r0 6 | 7 | HANDLER_CONSTANTS 8 | 9 | tf_next_pc: 10 | .word BAD 11 | 12 | HANDLER_END 13 | -------------------------------------------------------------------------------- /arch/arm/templates/blx_t2.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | /* Set link register. */ 4 | ldr.w lr, tf_next_pc 5 | /* Branch. */ 6 | ldr.w pc, tf_blx_t2_target 7 | 8 | HANDLER_CONSTANTS 9 | 10 | tf_blx_t2_target: 11 | .word BAD 12 | tf_next_pc: 13 | .word BAD 14 | 15 | HANDLER_END 16 | -------------------------------------------------------------------------------- /arch/arm/templates/cbz_t1.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_cond: 5 | tf_patch_rn: 6 | cbz r0, yes 7 | no: 8 | /* Condition false. */ 9 | ldr.w pc, tf_next_pc 10 | yes: 11 | /* Condition true. */ 12 | ldr.w pc, tf_cbz_t1_target 13 | 14 | HANDLER_CONSTANTS 15 | 16 | tf_next_pc: 17 | .word BAD 18 | tf_cbz_t1_target: 19 | .word BAD 20 | 21 | HANDLER_END 22 | -------------------------------------------------------------------------------- /arch/arm/templates/ldr_lit_t1.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_rt: 5 | ldr.n r0, tf_ldr_lit_t1_address 6 | tf_patch_rn2rt: 7 | tf_patch_rt2rt: 8 | /* The instruction below uses a different encoding, the transferred register rd is encoded as rm (on bits 0-2). */ 9 | ldr.n r0, [r1] 10 | /* Jump back. */ 11 | ldr.w pc, tf_next_pc 12 | 13 | HANDLER_CONSTANTS 14 | 15 | tf_ldr_lit_t1_address: 16 | .word BAD 17 | tf_next_pc: 18 | .word BAD 19 | 20 | HANDLER_END 21 | -------------------------------------------------------------------------------- /arch/arm/templates/ldr_lit_t2.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_patch_rt: 5 | ldr.w r0, tf_ldr_lit_t2_address 6 | tf_patch_rn2rt: 7 | tf_patch_rt2rt: 8 | ldr.w r0, [r1] 9 | /* Jump back. */ 10 | ldr.w pc, tf_next_pc 11 | 12 | HANDLER_CONSTANTS 13 | 14 | tf_ldr_lit_t2_address: 15 | .word BAD 16 | tf_next_pc: 17 | .word BAD 18 | 19 | HANDLER_END 20 | -------------------------------------------------------------------------------- /arch/arm/templates/thumb2_generic.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_insn: 5 | nop.w 6 | /* Jump back. */ 7 | ldr.w pc, tf_next_pc 8 | 9 | HANDLER_CONSTANTS 10 | 11 | tf_next_pc: 12 | .word BAD 13 | 14 | HANDLER_END 15 | -------------------------------------------------------------------------------- /arch/arm/templates/thumb_generic.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | 4 | tf_insn: 5 | nop 6 | /* Jump back. */ 7 | ldr.w pc, tf_next_pc 8 | 9 | HANDLER_CONSTANTS 10 | 11 | tf_next_pc: 12 | .word BAD 13 | 14 | HANDLER_END 15 | -------------------------------------------------------------------------------- /arch/arm/templates/thumb_nop.S: -------------------------------------------------------------------------------- 1 | #include "thumb_handler.h" 2 | HANDLER_BEGIN 3 | /* nop -- nothing to do, just jump back */ 4 | ldr.w pc, tf_next_pc 5 | HANDLER_CONSTANTS 6 | tf_next_pc: 7 | .word BAD 8 | 9 | HANDLER_END 10 | -------------------------------------------------------------------------------- /arch/arm/tests/Makefile: -------------------------------------------------------------------------------- 1 | # Warnings 2 | CFLAGS += -Wall -Wextra --std=gnu99 3 | 4 | # Generate debug symbols 5 | CFLAGS += -ggdb -O0 6 | 7 | ################################################################################ 8 | 9 | TESTCASES := testcases 10 | MAIN := main.c 11 | OUT := adbitest 12 | ADBISCRIPT := tests.as 13 | 14 | PY := $(wildcard *.py) 15 | ASM := $(PY:.py=.S) 16 | OBJ := $(ASM:.S=.o) 17 | MAINOBJ := $(MAIN:.c=.o) 18 | 19 | ################################################################################ 20 | 21 | all: $(OUT) $(ADBISCRIPT) 22 | 23 | clean: 24 | $(RM) $(OBJ) $(MAINOBJ) $(ASM) $(TESTCASES) $(OUT) $(ADBISCRIPT) $(MAIN) 25 | $(RM) *.pyc 26 | 27 | push : all 28 | adb push $(OUT) /data 29 | 30 | run : push 31 | adb shell /data/$(OUT) 32 | 33 | ################################################################################ 34 | 35 | $(OUT): $(OBJ) $(MAINOBJ) 36 | @echo " [LD] $@" 37 | $(CC) $(LDFLAGS) -o $@ $^ 38 | 39 | $(ADBISCRIPT): $(OUT) $(TESTCASES) 40 | @echo " [PY] $@" 41 | ./maketest < $(TESTCASES) > $(ADBISCRIPT) 42 | 43 | $(MAINOBJ) : %.o : %.c 44 | @echo " [CC] $@" 45 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 46 | 47 | $(ASM) : %.S : %.py 48 | @echo " [PY] $@" 49 | python $< > $@ 50 | 51 | $(MAIN): $(TESTCASES) 52 | @echo " [CC] $@" 53 | ./makemain < $(TESTCASES) > $(MAIN) 54 | 55 | $(TESTCASES): $(OBJ) 56 | @echo " [RE] $@" 57 | readelf --syms $^ | grep GLOBAL | grep -o test_.* | grep -v tinsn | sort -u > $@ 58 | 59 | $(OBJ) : %.o : %.S 60 | @echo " [AS] $@" 61 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 62 | 63 | ################################################################################ 64 | 65 | .PHONY : all clean push run 66 | .SILENT : 67 | 68 | ################################################################################ 69 | 70 | -------------------------------------------------------------------------------- /arch/arm/tests/adr_t1.py: -------------------------------------------------------------------------------- 1 | from test import * 2 | import random 3 | 4 | def test(rd, imm8): 5 | imm10 = imm8 << 2 6 | name = 'test_adr_t1_%s' % tn() 7 | cleanup = asm_wrap(name, rd) 8 | print '%s_tinsn:' % name 9 | print ' add.n %s, pc, #%i' % (rd, imm10) 10 | cleanup() 11 | 12 | def iter_cases(): 13 | while True: 14 | yield random.choice(LOWREGS), random.randint(0, 255) 15 | 16 | print ' .thumb' 17 | tests(test, iter_cases(), 30) -------------------------------------------------------------------------------- /arch/arm/tests/adr_t2.py: -------------------------------------------------------------------------------- 1 | from test import * 2 | import random 3 | 4 | print ' .thumb' 5 | 6 | def test(rd, imm12): 7 | name = 'test_adr_t2_%s' % tn() 8 | cleanup = asm_wrap(name, rd) 9 | print '%s_tinsn:' % name 10 | print ' sub.w %s, pc, #%i' % (rd, imm12) 11 | cleanup() 12 | 13 | 14 | def iter_cases(): 15 | while True: 16 | yield random.choice(T32REGS), random.randint(0, 4095) 17 | 18 | print ' .thumb' 19 | tests(test, iter_cases(), 30) -------------------------------------------------------------------------------- /arch/arm/tests/adr_t3.py: -------------------------------------------------------------------------------- 1 | from test import * 2 | import random 3 | 4 | print ' .thumb' 5 | 6 | def test(rd, imm12): 7 | name = 'test_adr_t3_%s' % tn() 8 | cleanup = asm_wrap(name, rd) 9 | print '%s_tinsn:' % name 10 | print ' add.w %s, pc, #%i' % (rd, imm12) 11 | cleanup() 12 | 13 | def iter_cases(): 14 | while True: 15 | yield random.choice(T32REGS), random.randint(0, 4095) 16 | 17 | print ' .thumb' 18 | tests(test, iter_cases(), 30) -------------------------------------------------------------------------------- /arch/arm/tests/arm_dp_imm.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | INSN = 'and eor sub rsb add adc sbc rsc tst teq cmp cmn orr mov bic mvn'.split() 7 | 8 | NORN = 'mov mvn'.split() 9 | NORD = 'cmp cmn tst teq'.split() 10 | 11 | def rotate(val, c): 12 | return ((val >> c) | (val << (32 - c))) & 0xffffffff 13 | 14 | def test(insn, s, flags, rd, rn, rnval, imm8, rot): 15 | name = 'test_dp_imm_%s' % tn() 16 | 17 | cleanup = asm_wrap(name, rd, {rn:rnval}, flags) 18 | 19 | print '%s_tinsn:' % name 20 | 21 | if 1: 22 | if insn in NORN: 23 | print ' %s%s %s, #%i, %i' % (insn, s, rd, imm8, rot) 24 | elif insn in NORD: 25 | print ' %s %s, #%i, %i' % (insn, rn, imm8, rot) 26 | else: 27 | print ' %s%s %s, %s, #%i, %i' % (insn, s, rd, rn, imm8, rot) 28 | else: 29 | v = rotate(imm8, rot) 30 | if insn in NORN: 31 | print ' %s%s %s, #%i // %x ror %i ' % (insn, s, rd, v, imm8, rot) 32 | elif insn in NORD: 33 | print ' %s %s, #%i // %x ror %i ' % (insn, rn, v, imm8, rot) 34 | else: 35 | print ' %s%s %s, %s, #%i // %x ror %i ' % (insn, s, rd, rn, v, imm8, rot) 36 | 37 | cleanup() 38 | 39 | def iter_cases(): 40 | while True: 41 | yield (random.choice(INSN), random.choice(['s', '']), 42 | random.randint(0, 0x1f), random.choice(T32REGS), 43 | random.choice(ALLREGS), random.randint(0, 0xffffffff), 44 | random.randint(0, 0xff), random.randint(0, 0xf) * 2) 45 | 46 | print ' .arm' 47 | tests(test, iter_cases(), 300) 48 | -------------------------------------------------------------------------------- /arch/arm/tests/arm_dp_reg.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | INSN = 'and eor sub rsb add adc sbc rsc tst teq cmp cmn orr mov bic mvn'.split() 7 | NORN = 'mov mvn'.split() 8 | NORD = 'cmp cmn tst teq'.split() 9 | 10 | def test(insn, s, flags, rd, rn, rnval, rm, rmval): 11 | name = 'test_dp_reg_%s' % tn() 12 | 13 | cleanup = asm_wrap(name, rd, {rn:rnval, rm:rmval}, flags) 14 | 15 | print '%s_tinsn:' % name 16 | 17 | if insn in NORN: 18 | print ' %s%s %s, %s' % (insn, s, rd, rm) 19 | elif insn in NORD: 20 | print ' %s %s, %s' % (insn, rn, rm) 21 | else: 22 | print ' %s%s %s, %s, %s' % (insn, s, rd, rn, rm) 23 | 24 | cleanup() 25 | 26 | def iter_cases(): 27 | while True: 28 | yield (random.choice(INSN), random.choice(['s', '']), 29 | random.randint(0, 0x1f), random.choice(T32REGS), 30 | random.choice(ALLREGS), random.randint(0, 0xffffffff), 31 | random.choice(ALLREGS), random.randint(0, 0xffffffff)) 32 | 33 | print ' .arm' 34 | tests(test, iter_cases(), 300) 35 | -------------------------------------------------------------------------------- /arch/arm/tests/b_a1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(flags, cond, direction): 7 | name = 'test_b_a1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0', {'r0':0}, flags) 10 | 11 | set_lr('%s_out' % name, False) 12 | 13 | print '%s_tinsn:' % name 14 | print ' b%s arm_fun_%s' % (cond, direction) 15 | print '%s_out:' % name 16 | cleanup() 17 | 18 | def iter_cases(): 19 | while True: 20 | yield random.randint(0, 0x1f), random.choice(COND), random.choice('fb') 21 | 22 | branch_helpers('b') 23 | print ' .arm' 24 | tests(test, iter_cases(), 30) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/b_t1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(flags, cond, direction): 7 | name = 'test_b_t1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0', {'r0':0}, flags) 10 | 11 | set_lr('%s_out' % name, True) 12 | 13 | print '%s_tinsn:' % name 14 | print ' b%s.n thumb_fun_%s' % (cond, direction) 15 | print '%s_out:' % name 16 | cleanup() 17 | 18 | def iter_cases(): 19 | while True: 20 | yield random.randint(0, 0x1f), random.choice(COND), random.choice('fb') 21 | 22 | branch_helpers('b') 23 | print ' .thumb' 24 | tests(test, iter_cases(), 5) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/b_t2.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(direction): 7 | name = 'test_b_t2_%s' % tn() 8 | cleanup = asm_wrap(name, 'r0') 9 | 10 | set_lr('%s_out' % name, True) 11 | 12 | print '%s_tinsn:' % name 13 | print ' b.n thumb_fun_%s' % direction 14 | 15 | print '%s_out:' % name 16 | cleanup() 17 | 18 | def iter_cases(): 19 | yield 'f' 20 | yield 'b' 21 | 22 | branch_helpers('b') 23 | print ' .thumb' 24 | tests(test, iter_cases(), 2) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/b_t3.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(flags, cond, direction): 7 | name = 'test_b_t3_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0', {'r0':0}, flags) 10 | 11 | set_lr('%s_out' % name, True) 12 | 13 | print '%s_tinsn:' % name 14 | print ' b%s.w thumb_fun_%s' % (cond, direction) 15 | print '%s_out:' % name 16 | cleanup() 17 | 18 | def iter_cases(): 19 | while True: 20 | yield random.randint(0, 0x1f), random.choice(COND), random.choice('fb') 21 | 22 | branch_helpers('b') 23 | print ' .thumb' 24 | tests(test, iter_cases(), 5) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/b_t4.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(direction): 7 | name = 'test_b_t4_%s' % tn() 8 | cleanup = asm_wrap(name, 'r0') 9 | 10 | set_lr('%s_out' % name, True) 11 | 12 | print '%s_tinsn:' % name 13 | print ' b.w thumb_fun_%s' % direction 14 | 15 | print '%s_out:' % name 16 | cleanup() 17 | 18 | def iter_cases(): 19 | yield 'f' 20 | yield 'b' 21 | 22 | branch_helpers('b') 23 | print ' .thumb' 24 | tests(test, iter_cases(), 2) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/bl_imm_a1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(direction): 7 | name = 'test_bl_imm_a1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | print ' mov r0, #0' 11 | print '%s_tinsn:' % name 12 | print ' bl arm_fun_%s' % (direction) 13 | cleanup() 14 | 15 | def iter_cases(): 16 | yield 'f' 17 | yield 'b' 18 | 19 | branch_helpers('b') 20 | print ' .arm' 21 | tests(test, iter_cases(), 30) 22 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/bl_t1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(direction): 7 | name = 'test_bl_t1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | print '%s_tinsn:' % name 11 | print ' bl.w thumb_fun_%s' % (direction) 12 | cleanup() 13 | 14 | def iter_cases(): 15 | yield 'f' 16 | yield 'b' 17 | 18 | branch_helpers('b') 19 | print ' .thumb' 20 | tests(test, iter_cases(), 30) 21 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/bl_t2.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(direction): 7 | name = 'test_blx_t2_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | print ' mov r0, #0' 11 | print '%s_tinsn:' % name 12 | print ' blx.w arm_fun_%s' % (direction) 13 | cleanup() 14 | 15 | def iter_cases(): 16 | yield 'f' 17 | yield 'b' 18 | 19 | branch_helpers('b') 20 | print ' .thumb' 21 | tests(test, iter_cases(), 30) 22 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/blx_imm_a2.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(direction): 7 | name = 'test_blx_imm_a2_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | print ' mov r0, #0' 11 | print '%s_tinsn:' % name 12 | print ' blx thumb_fun_%s' % (direction) 13 | cleanup() 14 | 15 | def iter_cases(): 16 | yield 'f' 17 | yield 'b' 18 | 19 | branch_helpers('b') 20 | print ' .arm' 21 | tests(test, iter_cases(), 30) 22 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/blx_reg_a1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(rm, fn): 7 | name = 'test_blx_reg_a1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | print ' adr %s, %s' % (rm, fn) 11 | if fn.startswith('thumb'): 12 | print ' orr %s, #1' % (rm) 13 | print '%s_tinsn:' % name 14 | print ' blx %s' % (rm) 15 | cleanup() 16 | 17 | def iter_cases(): 18 | fun = 'thumb_fun_b thumb_fun_f arm_fun_b arm_fun_f'.split() 19 | while True: 20 | yield random.choice(T32REGS), random.choice(fun) 21 | 22 | branch_helpers('b') 23 | print ' .arm' 24 | tests(test, iter_cases(), 30) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/blx_reg_t1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(rm, fn): 7 | name = 'test_blx_reg_t1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | print ' adr %s, %s' % (rm, fn) 11 | if fn.startswith('thumb'): 12 | print ' orr %s, #1' % (rm) 13 | print '%s_tinsn:' % name 14 | print ' blx.n %s' % (rm) 15 | cleanup() 16 | 17 | def iter_cases(): 18 | fun = 'thumb_fun_b thumb_fun_f arm_fun_b arm_fun_f'.split() 19 | while True: 20 | yield random.choice(T32REGS), random.choice(fun) 21 | 22 | branch_helpers('b') 23 | print ' .thumb' 24 | tests(test, iter_cases(), 30) 25 | branch_helpers('f') -------------------------------------------------------------------------------- /arch/arm/tests/branch.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def branch_helpers(dir): 4 | 5 | print ' .arm' 6 | print 'arm_fun_%s:' % dir 7 | print ' ldr r0, =%i' % random.randint(1, 0xffffffff) 8 | print ' bx lr' 9 | 10 | print ' .thumb' 11 | print 'thumb_fun_%s:' % dir 12 | print ' ldr r0, =%i' % random.randint(1, 0xffffffff) 13 | print ' bx lr' 14 | 15 | print ' .ltorg' 16 | 17 | def set_lr(symbol, thumb=False): 18 | print ' adr lr, %s /* artificially set the lr */' % symbol 19 | if thumb: 20 | print ' orr lr, #1 /* make sure lr points to thumb Thumb code */' 21 | -------------------------------------------------------------------------------- /arch/arm/tests/cbz_t1.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from test import * 4 | from branch import * 5 | 6 | def test(n, rn, zero, imm6): 7 | name = 'test_cbz_t1_%s' % tn() 8 | 9 | cleanup = asm_wrap(name, 'r0') 10 | 11 | if zero: 12 | print ' mov %s, #0' % rn 13 | else: 14 | print ' mov %s, #1' % rn 15 | 16 | print '%s_tinsn:' % name 17 | print ' cb%sz.n %s, %s_target' % (n, rn, name) 18 | print ' mov.w r0, #0' 19 | print ' b.w %s_out' % name 20 | for x in xrange(imm6 - 4): 21 | print ' .inst.n 0xbf00' 22 | print '%s_target:' % name 23 | print ' mov r0, #1' 24 | print '%s_out:' % name 25 | cleanup() 26 | 27 | def iter_cases(): 28 | while True: 29 | yield random.choice(['n', '']), random.choice(LOWREGS), random.randint(0, 1), random.randint(0, 1 << 6 - 1) 30 | 31 | print ' .thumb' 32 | tests(test, iter_cases(), 30) 33 | -------------------------------------------------------------------------------- /arch/arm/tests/ldr_lit_a1.py: -------------------------------------------------------------------------------- 1 | from test import * 2 | import random 3 | 4 | from literal import rubbish 5 | 6 | def test(rt, imm12): 7 | name = 'test_ldr_lit_a1_%s' % tn() 8 | cleanup = asm_wrap(name, rt) 9 | print '%s_tinsn:' % name 10 | print ' ldr %s, [pc, #%i]' % (rt, imm12) 11 | cleanup() 12 | 13 | 14 | def iter_cases(): 15 | while True: 16 | yield random.choice(T32REGS), random.randint(-(2 << 12 - 1), 2 << 12 - 1) 17 | 18 | print ' .arm' 19 | banner('random data') 20 | rubbish() 21 | banner('tests') 22 | tests(test, iter_cases(), 30) 23 | banner('random data') 24 | rubbish() 25 | -------------------------------------------------------------------------------- /arch/arm/tests/ldr_lit_t1.py: -------------------------------------------------------------------------------- 1 | from test import * 2 | import random 3 | 4 | print ' .thumb' 5 | 6 | from literal import rubbish 7 | 8 | def test(rt, imm8): 9 | imm10 = imm8 << 2 10 | name = 'test_ldr_lit_t1_%s' % tn() 11 | cleanup = asm_wrap(name, rt) 12 | print '%s_tinsn:' % name 13 | print ' ldr.n %s, [pc, #%i]' % (rt, imm10) 14 | cleanup() 15 | 16 | def iter_cases(): 17 | while True: 18 | yield random.choice(LOWREGS), random.randint(0, 0xff) 19 | 20 | print ' .thumb' 21 | banner('tests') 22 | tests(test, iter_cases(), 30) 23 | banner('random data') 24 | rubbish() 25 | -------------------------------------------------------------------------------- /arch/arm/tests/ldr_lit_t2.py: -------------------------------------------------------------------------------- 1 | from test import * 2 | import random 3 | 4 | print ' .thumb' 5 | 6 | from literal import rubbish 7 | 8 | def test(rt, imm12): 9 | name = 'test_ldr_lit_t2_%s' % tn() 10 | cleanup = asm_wrap(name, rt) 11 | print '%s_tinsn:' % name 12 | print ' ldr.w %s, [pc, #%i]' % (rt, imm12) 13 | cleanup() 14 | 15 | def iter_cases(): 16 | while True: 17 | yield random.choice(T32REGS), random.randint(-(2 << 12 - 1), 2 << 12 - 1) 18 | 19 | print ' .thumb' 20 | banner('random data') 21 | rubbish() 22 | banner('tests') 23 | tests(test, iter_cases(), 30) 24 | banner('random data') 25 | rubbish() 26 | -------------------------------------------------------------------------------- /arch/arm/tests/literal.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def rubbish(): 4 | '''Generate 4KB of random data.''' 5 | PERLINE = 8 6 | 7 | for a in xrange(4096 / PERLINE): 8 | data = ['0x%08x' % random.randint(0, 0xffffffff) for x in xrange(PERLINE + 1)] 9 | print ' .word %s' % (', '.join(data)) 10 | -------------------------------------------------------------------------------- /arch/arm/tests/makemain: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | symbols = sorted(l.strip() for l in sys.stdin if l.strip()) 6 | 7 | print r''' 8 | #include 9 | #include 10 | #include 11 | 12 | void handler(int sig_num, siginfo_t * info, void * ucontext) { 13 | (void) ucontext; 14 | fprintf(stderr, "Received signal %d (%s) at %p.\n", sig_num, strsignal(sig_num), info->si_addr); 15 | exit(0xe); 16 | } 17 | 18 | void install_handler() { 19 | struct sigaction sigact; 20 | sigact.sa_sigaction = handler; 21 | sigact.sa_flags = SA_RESTART | SA_SIGINFO; 22 | if (sigaction(SIGSEGV, &sigact, 0) || sigaction(SIGILL, &sigact, 0)) { 23 | fprintf(stderr, "Error installing signal handler.\n"); 24 | exit(1); 25 | } 26 | } 27 | 28 | ''' 29 | 30 | for symbol in symbols: 31 | print 'unsigned int %s();' % symbol 32 | 33 | print 34 | 35 | print 'int main() {' 36 | 37 | print ' install_handler(); ' 38 | #print ' *((int *) 0) = 10;' 39 | 40 | def human_name(s): 41 | return ' '.join(s.split('_')[1:]) 42 | 43 | for symbol in symbols: 44 | print ' printf("%%-32s %%08x\\n", "%s", %s()); ' % (human_name(symbol), symbol) 45 | 46 | print ' return 0;' 47 | 48 | print '}' -------------------------------------------------------------------------------- /arch/arm/tests/maketest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import bisect 4 | import sys 5 | import subprocess 6 | import struct 7 | 8 | symbols = sorted(l.strip() + '_tinsn' for l in sys.stdin if l.strip()) 9 | 10 | TEXTBASE = 0x8000 11 | 12 | def iter_addresses(symbols): 13 | cmd = ['readelf', '--syms', 'adbitest'] 14 | for line in subprocess.check_output(cmd).split('\n'): 15 | line = line.split() 16 | try: 17 | symbol = line[-1] 18 | if symbol in symbols: 19 | address = int(line[1], 16) 20 | yield address - TEXTBASE 21 | except (IndexError, ValueError): 22 | pass 23 | 24 | addresses = list(iter_addresses(symbols)) 25 | 26 | def iter_mapping(): 27 | cmd = ['readelf', '--syms', 'adbitest'] 28 | for line in subprocess.check_output(cmd).split('\n'): 29 | try: 30 | line = line.split() 31 | name = line[7] 32 | addr = int(line[1], 16) 33 | if name.startswith('$'): 34 | yield addr - TEXTBASE, name 35 | except (IndexError, ValueError): 36 | pass 37 | 38 | mapping = sorted(iter_mapping()) 39 | 40 | def kind(address): 41 | i = bisect.bisect_right(mapping, (address, '$z')) 42 | if i: 43 | v = mapping[i - 1][1] 44 | d = {'$a': 'arm', '$t': 'thumb'} 45 | return d[v] 46 | raise ValueError 47 | 48 | def opcode(address, kind): 49 | with open('adbitest', 'r') as f: 50 | f.seek(address) 51 | if kind == 'thumb': 52 | insn = struct.unpack('= 0xe800: 54 | insn <<= 16 55 | insn |= struct.unpack(' 0xe800 and k == 'thumb': 72 | k = 'thumb2' 73 | 74 | print 'tracepoint add /data/adbitest dummy_handler 0x%08x 0x%08x %s' % (address, o, k) 75 | -------------------------------------------------------------------------------- /arch/arm/trap.c: -------------------------------------------------------------------------------- 1 | #include "tracepoint/jump.h" 2 | #include "process/process.h" 3 | #include "process/thread.h" 4 | #include "procutil/ptrace.h" 5 | #include "process/linker.h" 6 | 7 | bool thread_trap(thread_t * thread) { 8 | 9 | pt_regs regs; 10 | address_t ip, jump_target; 11 | 12 | if (unlikely(!thread_get_regs(thread, ®s))) { 13 | /* Thread died while reading registers. Consider this case as handled. */ 14 | return true; 15 | } 16 | 17 | ip = instruction_pointer(®s); 18 | jump_target = jump_get(thread->process, ip); 19 | 20 | debug("Thread %s hit a break at %s.", str_thread(thread), str_address(thread->process, ip)); 21 | 22 | #if 0 /* enable to see full context on each hit */ 23 | dump_thread(thread); 24 | #endif 25 | 26 | if (likely(jump_target)) { 27 | /* Thread hit a tracepoint. Change the PC and let it continue. */ 28 | if (likely(!thread->process->stabilizing)) { 29 | debug("Thread %s jumping to %s.", str_thread(thread), str_address(thread->process, jump_target)); 30 | regs.ARM_pc = jump_target; 31 | if (likely(thread_set_regs(thread, ®s))) { 32 | thread_continue_or_stop(thread, 0); 33 | } 34 | } else { 35 | /* The process is currently stabilizing threads. The current thread just hit a tracepoint, but we don't 36 | * change its address to the trampoline, we just leave it stopped. If we continue the thread now, it 37 | * will hit the tracepoint again. */ 38 | info("Thread %s is stabilizing, deferring jump to %s.", str_thread(thread), 39 | str_address(thread->process, jump_target)); 40 | } 41 | return true; 42 | } 43 | 44 | /* Linker breakpoint */ 45 | if (likely(ip == thread->process->linker.bkpt)) { 46 | /* Linker breakpoint */ 47 | linker_notify(thread); 48 | regs.ARM_pc = regs.ARM_lr; 49 | if (likely(thread_set_regs(thread, ®s))) { 50 | thread_continue_or_stop(thread, 0); 51 | } 52 | return true; 53 | } 54 | 55 | return false; 56 | } 57 | -------------------------------------------------------------------------------- /arch/arm64/include/template_field.h: -------------------------------------------------------------------------------- 1 | /* 2 | * template_field.h 3 | */ 4 | 5 | #ifndef ARCH_ARM64_INCLUDE_TEMPLATE_FIELD_H_ 6 | #define ARCH_ARM64_INCLUDE_TEMPLATE_FIELD_H_ 7 | 8 | typedef enum template_field_id_t { 9 | 10 | /* End marker */ 11 | TF_NULL = 0, 12 | 13 | /* Insert the original traced instruction opcode */ 14 | TF_INSN, 15 | 16 | /* Absolute address of the high-level handler */ 17 | TF_HANDLER_ADDRESS, 18 | 19 | /* Insert the address of the traced instruction. */ 20 | //TF_ORIG_PC, 21 | 22 | /* Insert the address of the instruction following the traced instruction */ 23 | TF_NEXT_PC, 24 | 25 | /* Calculate address pc + imm19 */ 26 | TF_RELATIVE_IMM19_ADDR, 27 | 28 | /* Calculate address pc + imm26 */ 29 | TF_RELATIVE_IMM26_ADDR, 30 | 31 | /*** Instruction patching ***/ 32 | /* Copy condition of b instruction */ 33 | TF_PATCH_COND, 34 | 35 | /* Copy sf bit */ 36 | TF_PATCH_SF2SF, 37 | 38 | /* Copy op bit */ 39 | TF_PATCH_OP2OP, 40 | 41 | /* Patch Rn to original instruction Rn */ 42 | TF_PATCH_RN2RN, 43 | /* Patch Rt to original instruction Rt */ 44 | TF_PATCH_RT2RT, 45 | /* Patch Rn to original instruction Rt */ 46 | TF_PATCH_RN2RT, 47 | 48 | TF_PATCH_B40_2_B40, 49 | 50 | TF_PATCH_LDR_SIZE_LIT2REG, 51 | 52 | TF_ADRP_RESULT, 53 | 54 | /*** Return from trampoline ***/ 55 | /* Return to the address of the instruction following the traced instruction */ 56 | TF_HANDLER_RETURN, 57 | 58 | /* Return to the address PC + imm26 of the traced instruction */ 59 | TF_HANDLER_RETURN_TO_IMM26, 60 | 61 | /* Return to the address PC + imm19 of the traced instruction */ 62 | TF_HANDLER_RETURN_TO_IMM19, 63 | 64 | /* Return to the address PC + imm14 of the traced instruction */ 65 | TF_HANDLER_RETURN_TO_IMM14, 66 | 67 | } template_field_id_t; 68 | 69 | #endif /* ARCH_ARM64_INCLUDE_TEMPLATE_FIELD_H_ */ 70 | -------------------------------------------------------------------------------- /arch/arm64/templates/Makefile: -------------------------------------------------------------------------------- 1 | SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))$(SELF_DIR) 2 | T2C := $(SELF_DIR)/t2c 3 | 4 | SRC := $(shell find . -maxdepth 1 -name "*.S") 5 | OBJ := $(SRC:.S=.o) 6 | 7 | OUT := templates.c 8 | OUT_HEAD := $(OUT:.c=.h) 9 | 10 | CC := $(CCv8) 11 | CFLAGS += -march=armv8-a -ggdb3 -O0 12 | 13 | all: $(OUT) $(OUT_HEAD) 14 | 15 | $(OBJ): %.o : %.S 16 | @echo " [TMP] $@" 17 | @$(CC) $(CFLAGS) -c -o $@ $< 18 | 19 | $(OUT): $(OBJ) 20 | @echo " [T2C] $@" 21 | @$(T2C) -o $@ $^ 22 | touch $@ 23 | 24 | $(OUT_HEAD): $(OBJ) 25 | @echo " [T2H] $@" 26 | @$(T2C) -o $@ -H $^ 27 | touch $@ 28 | 29 | clean: 30 | @$(RM) $(OBJ) $(OUT) $(OUT_HEAD) 31 | 32 | .PHONY: clean 33 | 34 | 35 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_adrp.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_patch_rt2rt: 8 | ldr x16, tf_adrp_result 9 | HANDLER_OOL_RETURN() 10 | 11 | HANDLER_OOL_END 12 | 13 | tf_adrp_result: 14 | .dword BADADDR; 15 | 16 | HANDLER_END 17 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_b.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | HANDLER_OOL_RETURN(_to_imm26_) 8 | 9 | HANDLER_OOL_END 10 | 11 | HANDLER_END 12 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_b_cond.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_patch_cond: 8 | b.al yes; 9 | no: 10 | HANDLER_OOL_RETURN() 11 | yes: 12 | HANDLER_OOL_RETURN(_to_imm19_) 13 | 14 | HANDLER_OOL_END 15 | 16 | HANDLER_END 17 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_bl.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | ldr x30, tf_next_pc; 8 | 9 | #ifdef USE_X16_IN_BL_TRAMPOLINE 10 | ldr x16, tf_relative_imm26_addr; 11 | br x16; 12 | #else 13 | HANDLER_OOL_RETURN(_to_imm26_) 14 | #endif 15 | 16 | HANDLER_OOL_END 17 | 18 | #ifdef USE_X16_IN_BL_TRAMPOLINE 19 | 20 | tf_relative_imm26_addr: 21 | .dword BADADDR; 22 | 23 | #endif 24 | 25 | HANDLER_END 26 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_blr.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | ldr x30, tf_next_pc; 8 | 9 | tf_patch_rn2rn: 10 | br x16; 11 | 12 | HANDLER_OOL_END 13 | 14 | HANDLER_END 15 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_blr_x30.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | mov x16, x30 8 | ldr x30, tf_next_pc; 9 | br x16; 10 | 11 | HANDLER_OOL_END 12 | 13 | HANDLER_END 14 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_br.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | /* trampoline for br and ret instructions */ 4 | 5 | HANDLER_BEGIN 6 | 7 | HANDLER_OOL_BEGIN 8 | 9 | tf_patch_rn2rn: 10 | br x16 11 | 12 | HANDLER_OOL_END 13 | 14 | HANDLER_END 15 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_cbnz.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_patch_sf2sf: 8 | tf_patch_op2op: 9 | tf_patch_rt2rt: 10 | cbz x16, yes; 11 | no: 12 | HANDLER_OOL_RETURN() 13 | yes: 14 | HANDLER_OOL_RETURN(_to_imm19_) 15 | 16 | HANDLER_OOL_END 17 | 18 | HANDLER_END 19 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_generic.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_insn: 8 | nop; 9 | 10 | HANDLER_OOL_RETURN() 11 | 12 | HANDLER_OOL_END 13 | 14 | HANDLER_END 15 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_ldr_literal.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_patch_rt2rt_0: 8 | ldr x16, tf_relative_imm19_addr 9 | tf_patch_rt2rt_1: 10 | tf_patch_rn2rt: 11 | tf_patch_ldr_size_lit2reg: 12 | ldr x16, [x16] 13 | 14 | HANDLER_OOL_RETURN() 15 | 16 | HANDLER_OOL_END 17 | 18 | tf_relative_imm19_addr: 19 | .dword BADADDR 20 | 21 | HANDLER_END 22 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_ldrsw_literal.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_patch_rt2rt_0: 8 | ldr x16, tf_relative_imm19_addr 9 | tf_patch_rt2rt_1: 10 | tf_patch_rn2rt: 11 | ldrsw x16, [x16] 12 | 13 | HANDLER_OOL_RETURN() 14 | 15 | HANDLER_OOL_END 16 | 17 | tf_relative_imm19_addr: 18 | .dword BADADDR 19 | 20 | HANDLER_END 21 | -------------------------------------------------------------------------------- /arch/arm64/templates/a64_tbnz.S: -------------------------------------------------------------------------------- 1 | #include "a64_handler.h" 2 | 3 | HANDLER_BEGIN 4 | 5 | HANDLER_OOL_BEGIN 6 | 7 | tf_patch_sf2sf: /* b5 */ 8 | tf_patch_b40_2_b40_: 9 | tf_patch_op2op: 10 | tf_patch_rt2rt: 11 | tbz x16, #0, yes; 12 | no: 13 | HANDLER_OOL_RETURN() 14 | yes: 15 | HANDLER_OOL_RETURN(_to_imm14_) 16 | 17 | HANDLER_OOL_END 18 | 19 | HANDLER_END 20 | -------------------------------------------------------------------------------- /arch/arm64/tests/Makefile: -------------------------------------------------------------------------------- 1 | # Warnings 2 | CFLAGS += -Wall -Wextra --std=gnu99 3 | 4 | # Generate debug symbols 5 | CFLAGS += -ggdb -O0 6 | 7 | # Position independent 8 | CFLAGS += -fPIE 9 | LDFLAGS += -pie 10 | 11 | 12 | AS := $(CC:gcc=as) 13 | 14 | IDK ?= ../../../idk 15 | MKINJ ?= $(IDK)/mkinj 16 | ADBICACHE ?= $(IDK)/adbicache 17 | 18 | ################################################################################ 19 | 20 | TESTCASES := testcases 21 | MAIN := main.c 22 | OUT := adbitest 23 | ADBI := adbitest.adbi 24 | INJ := adbitest.inj 25 | 26 | PY := $(filter-out common.py,$(wildcard *.py)) 27 | ASM := $(PY:.py=.S) 28 | OBJ := $(ASM:.S=.o) 29 | MAINOBJ := $(MAIN:.c=.o) 30 | OBJCACHE := $(OUT).ac 31 | 32 | ################################################################################ 33 | 34 | all: $(OUT) $(INJ) 35 | 36 | clean: 37 | $(RM) $(OBJ) $(MAINOBJ) $(ASM) $(OBJCACHE) $(TESTCASES) $(OUT) $(ADBI) $(INJ) $(MAIN) 38 | $(RM) *.pyc 39 | 40 | push : all 41 | adb push $(OUT) /data 42 | adb push $(INJ) /data 43 | 44 | ################################################################################ 45 | 46 | $(OUT): $(OBJ) $(MAINOBJ) 47 | @echo " [LD] $@" 48 | $(CC) $(LDFLAGS) -o $@ $^ 49 | 50 | $(OBJCACHE): $(OUT) 51 | @echo " [AC] $@" 52 | $(ADBICACHE) $(OUT) 53 | 54 | $(INJ): $(OUT) $(ADBI) $(ADBICACHE) 55 | @echo " [INJ] $@" 56 | $(MKINJ) --gcc $(CC) --binary /data/adbitest $(ADBI) 57 | 58 | $(MAINOBJ) : %.o : %.c 59 | @echo " [CC] $@" 60 | $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 61 | 62 | $(ASM) $(ADBI) : mktest.intermediate 63 | .INTERMEDIATE: mktest.inermediate 64 | 65 | mktest.intermediate: $(PY) 66 | @echo " [MKT] adbitest.adbi" 67 | ./mktest 68 | 69 | $(MAIN): $(TESTCASES) 70 | @echo " [MKM] $@" 71 | ./mkmain < $(TESTCASES) > $(MAIN) 72 | 73 | $(TESTCASES): $(OBJ) 74 | @echo " [RE] $@" 75 | readelf -W --syms $^ | grep GLOBAL | grep -o test_.* | grep -v tinsn | sort -u > $@ 76 | 77 | $(OBJ) : %.o : %.S 78 | @echo " [AS] $@" 79 | $(AS) -c $< -o $@ 80 | 81 | ################################################################################ 82 | 83 | .PHONY : all clean push run 84 | .SILENT : 85 | 86 | ################################################################################ 87 | 88 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_adrp.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_adrp(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'insn' : random.choice(['adrp', 'adr']), 9 | 'res' : random.choice(GPREGS64), 10 | 'label': random.choice(self.symbols)} 11 | 12 | symbols = [__name__ + '_addr_' + str(i) for i in xrange(16)] 13 | 14 | def test_begin(self): 15 | yield ' .arch armv8-a' 16 | yield ' .align 2' 17 | yield ' .text' 18 | for i in xrange(0, len(self.symbols), 3): 19 | yield self.symbols[i] + ':' 20 | yield ' nop' 21 | yield ' .skip %d' % random.randrange(1024, 3072, 4) 22 | yield ' .text' 23 | 24 | def gen_testcase(self, nr, insn, res, label): 25 | state = ProcessorState([res]) 26 | yield state.prepare() 27 | yield self.testcase_insn(nr, '{insn}\t{res}, {label}'.format(**locals())) 28 | l = 'pageof:' + label if insn == 'adrp' else label 29 | yield state.check({res:l}) 30 | yield state.restore() 31 | 32 | def test_end(self): 33 | yield ' .align 2' 34 | yield ' .text' 35 | for i in xrange(1, len(self.symbols), 3): 36 | yield self.symbols[i] + ':' 37 | yield ' nop' 38 | yield ' .skip %d' % random.randrange(1024, 3072, 4) 39 | yield ' .data' 40 | for i in xrange(2, len(self.symbols), 3): 41 | yield self.symbols[i] + ':' 42 | yield ' nop' 43 | yield ' .skip %d' % random.randrange(1025, 3071) 44 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_b.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_b(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'label_idx': random.randint(0, self.__label_count - 1)} 9 | 10 | def __init__(self): 11 | self.__label_count = 8 12 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 13 | self.randvals = random.sample(xrange(0, 0xfffffffffffffff), self.__label_count) 14 | 15 | def test_begin(self): 16 | yield ' .arch armv8-a' 17 | yield ' .align 2' 18 | yield ' .text' 19 | for i in xrange(0, len(self.symbols), 2): 20 | yield self.symbols[i] + ':' 21 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 22 | yield ' ret' 23 | yield ' .skip %d' % random.randrange(512, 2048, 4) 24 | 25 | def gen_testcase(self, nr, label_idx): 26 | label = self.symbols[label_idx] 27 | ret_label = self.testcase_name(nr) + '_ret' 28 | state = ProcessorState(setreg={'x30':ret_label}, reserve=['x0']) 29 | yield state.prepare() 30 | yield self.testcase_insn(nr, 'b\t\t{0}'.format(label)) 31 | yield ret_label + ':' 32 | yield state.check({'x0':self.randvals[label_idx]}) 33 | yield state.restore() 34 | 35 | def test_end(self): 36 | for i in xrange(1, len(self.symbols), 2): 37 | yield ' .skip %d' % random.randrange(512, 2048, 4) 38 | yield self.symbols[i] + ':' 39 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 40 | yield ' ret' 41 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_b_cond.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_b_cond(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'nzcv' : random.randint(0, 0xf), 9 | 'cond' : random.choice(COND), 10 | 'label_idx': random.randint(0, self.__label_count - 1)} 11 | 12 | def __init__(self): 13 | self.__label_count = 8 14 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 15 | randvals = random.sample(xrange(0, 0xfffffffffffffff), 2*self.__label_count) 16 | self.branch = randvals[:self.__label_count] 17 | self.nobranch = randvals[self.__label_count:] 18 | 19 | def test_begin(self): 20 | yield ' .arch armv8-a' 21 | yield ' .align 2' 22 | yield ' .text' 23 | for i in xrange(0, len(self.symbols), 2): 24 | yield self.symbols[i] + ':' 25 | yield ' ldr\t\tx0, ={0}'.format(hex(self.branch[i])) 26 | yield ' ret' 27 | yield ' .skip %d' % random.randrange(512, 2048, 4) 28 | 29 | def gen_testcase(self, nr, nzcv, cond, label_idx): 30 | label = self.symbols[label_idx] 31 | ret_label = self.testcase_name(nr) + '_ret' 32 | state = ProcessorState(setreg={'nzcv':nzcv, 33 | 'x0':self.nobranch[label_idx], 34 | 'x30':ret_label}, 35 | reserve=['x0']) 36 | yield state.prepare() 37 | yield self.testcase_insn(nr, 'b.{cond}\t{label}'.format(**locals())) 38 | yield ret_label + ':' 39 | if check_nzcv_cond(nzcv, cond): 40 | yield ' // should jump' 41 | x0 = self.branch[label_idx] 42 | else: 43 | yield ' // shouldn\'t jump' 44 | x0 = self.nobranch[label_idx] 45 | yield state.check({'x0':x0}) 46 | yield state.restore() 47 | 48 | def test_end(self): 49 | for i in xrange(1, len(self.symbols), 2): 50 | yield ' .skip %d' % random.randrange(512, 2048, 4) 51 | yield self.symbols[i] + ':' 52 | yield ' ldr\t\tx0, ={0}'.format(hex(self.branch[i])) 53 | yield ' ret' 54 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_bl.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_bl(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'label_idx': random.randint(0, self.__label_count - 1)} 9 | 10 | def __init__(self): 11 | self.__label_count = 8 12 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 13 | self.randvals = random.sample(xrange(0, 0xfffffffffffffff), self.__label_count) 14 | 15 | def test_begin(self): 16 | yield ' .arch armv8-a' 17 | yield ' .align 2' 18 | yield ' .text' 19 | for i in xrange(0, len(self.symbols), 2): 20 | yield self.symbols[i] + ':' 21 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 22 | yield ' mov\t\tx1, x30' 23 | yield ' ret' 24 | yield ' .skip %d' % random.randrange(512, 2048, 4) 25 | 26 | def gen_testcase(self, nr, label_idx): 27 | label = self.symbols[label_idx] 28 | ret_label = self.testcase_name(nr) + '_ret' 29 | state = ProcessorState(store=['x30'], reserve=['x0', 'x1']) 30 | yield state.prepare() 31 | yield self.testcase_insn(nr, 'bl\t\t{0}'.format(label)) 32 | yield ret_label + ':' 33 | yield state.check({'x0':self.randvals[label_idx], 34 | 'x1':ret_label}) 35 | yield state.restore() 36 | 37 | def test_end(self): 38 | for i in xrange(1, len(self.symbols), 2): 39 | yield ' .skip %d' % random.randrange(512, 2048, 4) 40 | yield self.symbols[i] + ':' 41 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 42 | yield ' mov\t\tx1, x30' 43 | yield ' ret' 44 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_blr.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_blr(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'reg': random.choice(GPREGS64 + ['x30']), 9 | 'label_idx': random.randint(0, self.__label_count - 1)} 10 | 11 | def __init__(self): 12 | self.__label_count = 8 13 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 14 | self.randvals = random.sample(xrange(0, 0xfffffffffffffff), self.__label_count) 15 | 16 | def test_begin(self): 17 | yield ' .arch armv8-a' 18 | yield ' .align 2' 19 | yield ' .text' 20 | for i in xrange(0, len(self.symbols), 2): 21 | yield self.symbols[i] + ':' 22 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 23 | yield ' mov\t\tx1, x30' 24 | yield ' ret' 25 | yield ' .skip %d' % random.randrange(512, 2048, 4) 26 | 27 | def gen_testcase(self, nr, reg, label_idx): 28 | label = self.symbols[label_idx] 29 | ret_label = self.testcase_name(nr) + '_ret' 30 | state = ProcessorState(setreg={reg:label}, reserve=['x0', 'x1'], store=['x30']) 31 | yield state.prepare() 32 | yield self.testcase_insn(nr, 'blr\t\t{0}'.format(reg)) 33 | yield ret_label + ':' 34 | yield state.check({'x0':self.randvals[label_idx], 35 | 'x1':ret_label}) 36 | yield state.restore() 37 | 38 | def test_end(self): 39 | for i in xrange(1, len(self.symbols), 2): 40 | yield ' .skip %d' % random.randrange(512, 2048, 4) 41 | yield self.symbols[i] + ':' 42 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 43 | yield ' mov\t\tx1, x30' 44 | yield ' ret' 45 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_br.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_br(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'reg': random.choice(GPREGS64), 9 | 'label_idx': random.randint(0, self.__label_count - 1)} 10 | 11 | def __init__(self): 12 | self.__label_count = 8 13 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 14 | self.randvals = random.sample(xrange(0, 0xfffffffffffffff), self.__label_count) 15 | 16 | def test_begin(self): 17 | yield ' .arch armv8-a' 18 | yield ' .align 2' 19 | yield ' .text' 20 | for i in xrange(0, len(self.symbols), 2): 21 | yield self.symbols[i] + ':' 22 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 23 | yield ' ret' 24 | yield ' .skip %d' % random.randrange(512, 2048, 4) 25 | 26 | def gen_testcase(self, nr, reg, label_idx): 27 | label = self.symbols[label_idx] 28 | ret_label = self.testcase_name(nr) + '_ret' 29 | state = ProcessorState(setreg={reg: label, 'x30':ret_label}, reserve=['x0']) 30 | yield state.prepare() 31 | yield self.testcase_insn(nr, 'br\t\t{0}'.format(reg)) 32 | yield ret_label + ':' 33 | yield state.check({'x0':self.randvals[label_idx]}) 34 | yield state.restore() 35 | 36 | def test_end(self): 37 | for i in xrange(1, len(self.symbols), 2): 38 | yield ' .skip %d' % random.randrange(512, 2048, 4) 39 | yield self.symbols[i] + ':' 40 | yield ' ldr\t\tx0, ={0}'.format(hex(self.randvals[i])) 41 | yield ' ret' 42 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_cbnz.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_cbnz(TemplateTest): 5 | 6 | def gen_rand(self): 7 | regs = list(set(GPREGS) - {'x0', 'w0'}) 8 | while True: 9 | yield {'insn' : random.choice(['cbz', 'cbnz']), 10 | 'reg' : random.choice(regs), 11 | 'val' : random.randint(0,1), 12 | 'label_idx': random.randint(0, self.__label_count - 1)} 13 | 14 | def __init__(self): 15 | self.__label_count = 8 16 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 17 | randvals = random.sample(xrange(0, 0xfffffffffffffff), 2*self.__label_count) 18 | self.branch = randvals[:self.__label_count] 19 | self.nobranch = randvals[self.__label_count:] 20 | 21 | def test_begin(self): 22 | yield ' .arch armv8-a' 23 | yield ' .align 2' 24 | yield ' .text' 25 | for i in xrange(0, len(self.symbols), 2): 26 | yield self.symbols[i] + ':' 27 | yield ' ldr\t\tx0, ={0}'.format(hex(self.branch[i])) 28 | yield ' ret' 29 | yield ' .skip %d' % random.randrange(512, 2048, 4) 30 | 31 | def gen_testcase(self, nr, insn, reg, val, label_idx): 32 | label = self.symbols[label_idx] 33 | ret_label = self.testcase_name(nr) + '_ret' 34 | if val != 0: 35 | val = random.randint(1,0xffffffff) 36 | state = ProcessorState(setreg={reg:val, 37 | 'x0':self.nobranch[label_idx], 38 | 'x30':ret_label}, 39 | reserve=['x0']) 40 | yield state.prepare() 41 | space = '\t' if insn == 'cbnz' else '\t\t' 42 | yield self.testcase_insn(nr, '{insn}{space}{reg}, {label}'.format(**locals())) 43 | yield ret_label + ':' 44 | if (insn == 'cbz' and val == 0) or (insn == 'cbnz' and val != 0): 45 | yield ' // should jump' 46 | x0 = self.branch[label_idx] 47 | else: 48 | yield ' // shouldn\'t jump' 49 | x0 = self.nobranch[label_idx] 50 | yield state.check({'x0':x0}) 51 | yield state.restore() 52 | 53 | def test_end(self): 54 | for i in xrange(1, len(self.symbols), 2): 55 | yield ' .skip %d' % random.randrange(512, 2048, 4) 56 | yield self.symbols[i] + ':' 57 | yield ' ldr\t\tx0, ={0}'.format(hex(self.branch[i])) 58 | yield ' ret' 59 | -------------------------------------------------------------------------------- /arch/arm64/tests/a64_ldr_literal.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_ldr_literal(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'reg' : random.choice(GPREGS), 9 | 'label_idx': random.randint(0, self.__label_count - 1)} 10 | 11 | def __init__(self): 12 | self.__label_count = 12 13 | self.symbols = [__name__ + '_addr_' + str(i) for i in xrange(self.__label_count)] 14 | self.randvals = random.sample(xrange(0, 0xfffffffffffffff), self.__label_count) 15 | 16 | def test_begin(self): 17 | yield ' .arch armv8-a' 18 | yield ' .align 2' 19 | yield ' .text' 20 | for i in xrange(0, len(self.symbols), 2): 21 | yield self.symbols[i] + ':' 22 | yield ' .dword %s' % hex(self.randvals[i]) 23 | yield ' .skip %d' % random.randrange(512, 2048, 4) 24 | yield ' .text' 25 | 26 | def gen_testcase(self, nr, reg, label_idx): 27 | label = self.symbols[label_idx] 28 | val = self.randvals[label_idx] 29 | if reg.startswith('w'): 30 | val &= 0xffffffff 31 | state = ProcessorState(save=[reg]) 32 | yield state.prepare() 33 | yield self.testcase_insn(nr, 'ldr\t\t{reg}, {label}'.format(**locals())) 34 | yield state.check({reg:val}) 35 | yield state.restore() 36 | 37 | def test_end(self): 38 | yield ' .align 2' 39 | yield ' .text' 40 | for i in xrange(1, len(self.symbols), 2): 41 | yield self.symbols[i] + ':' 42 | yield ' .dword %s' % hex(self.randvals[i]) 43 | yield ' .skip %d' % random.randrange(512, 2048, 4) -------------------------------------------------------------------------------- /arch/arm64/tests/a64_ldrsw_literal.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_ldrsw_literal(TemplateTest): 5 | 6 | def gen_rand(self): 7 | while True: 8 | yield {'reg' : random.choice(GPREGS64), 9 | 'label_idx': random.randint(0, self.__label_count - 1)} 10 | 11 | def __init__(self): 12 | self.__label_count = 12 13 | self.symbols = [__name__ + '_addr_' + str(i) for i in xrange(self.__label_count)] 14 | self.randvals = random.sample(xrange(0, 0xffffffff), self.__label_count) 15 | def test_begin(self): 16 | yield ' .arch armv8-a' 17 | yield ' .align 2' 18 | yield ' .text' 19 | for i in xrange(0, len(self.symbols), 2): 20 | yield self.symbols[i] + ':' 21 | yield ' .word %s' % hex(self.randvals[i]) 22 | yield ' .skip %d' % random.randrange(512, 2048, 4) 23 | yield ' .text' 24 | 25 | def gen_testcase(self, nr, reg, label_idx): 26 | label = self.symbols[label_idx] 27 | val = self.randvals[label_idx] 28 | if val > 0x7fffffff: 29 | assert len(hex(val)) == 10 30 | val = '0xffffffff' + hex(val)[2:] 31 | state = ProcessorState(save=[reg]) 32 | yield state.prepare() 33 | yield self.testcase_insn(nr, 'ldrsw\t\t{reg}, {label}'.format(**locals())) 34 | yield state.check({reg:val}) 35 | yield state.restore() 36 | 37 | def test_end(self): 38 | yield ' .align 2' 39 | yield ' .text' 40 | for i in xrange(1, len(self.symbols), 2): 41 | yield self.symbols[i] + ':' 42 | yield ' .word %s' % hex(self.randvals[i]) 43 | yield ' .skip %d' % random.randrange(512, 2048, 4) -------------------------------------------------------------------------------- /arch/arm64/tests/a64_tbnz.py: -------------------------------------------------------------------------------- 1 | import random 2 | from common import * 3 | 4 | class test_a64_tbnz(TemplateTest): 5 | 6 | def gen_rand(self): 7 | regs = list(set(GPREGS) - {'x0', 'w0'}) 8 | while True: 9 | yield {'insn' : random.choice(['tbz', 'tbnz']), 10 | 'reg' : random.choice(regs), 11 | 'bit' : random.randint(0,63), 12 | 'val' : random.randint(0,1), 13 | 'label_idx': random.randint(0, self.__label_count - 1)} 14 | 15 | def __init__(self): 16 | self.__label_count = 8 17 | self.symbols = [ __name__ + '_addr_' + str(i) for i in xrange(self.__label_count) ] 18 | randvals = random.sample(xrange(0, 0xfffffffffffffff), 2*self.__label_count) 19 | self.branch = randvals[:self.__label_count] 20 | self.nobranch = randvals[self.__label_count:] 21 | 22 | def test_begin(self): 23 | yield ' .arch armv8-a' 24 | yield ' .align 2' 25 | yield ' .text' 26 | for i in xrange(0, len(self.symbols), 2): 27 | yield self.symbols[i] + ':' 28 | yield ' ldr\t\tx0, ={0}'.format(hex(self.branch[i])) 29 | yield ' ret' 30 | yield ' .skip %d' % random.randrange(512, 2048, 4) 31 | 32 | def gen_testcase(self, nr, insn, reg, bit, val, label_idx): 33 | label = self.symbols[label_idx] 34 | ret_label = self.testcase_name(nr) + '_ret' 35 | if reg.startswith('w'): 36 | v = random.randint(0,0xffffffff) 37 | bit /= 2 38 | else: 39 | v = random.randint(0,0xfffffffffffffff) 40 | 41 | if val == 1: 42 | v |= (0x1 << bit) 43 | else: 44 | v &= ~(0x1 << bit) 45 | 46 | state = ProcessorState(setreg={reg:v, 47 | 'x0':self.nobranch[label_idx], 48 | 'x30':ret_label}, 49 | reserve=['x0']) 50 | yield state.prepare() 51 | space = '\t' if insn == 'tbnz' else '\t\t' 52 | yield self.testcase_insn(nr, '{insn}{space}{reg}, #{bit}, {label}'.format(**locals())) 53 | yield ret_label + ':' 54 | if (insn == 'tbz' and val == 0) or (insn == 'tbnz' and val != 0): 55 | yield ' // should jump' 56 | x0 = self.branch[label_idx] 57 | else: 58 | yield ' // shouldn\'t jump' 59 | x0 = self.nobranch[label_idx] 60 | yield state.check({'x0':x0}) 61 | yield state.restore() 62 | 63 | def test_end(self): 64 | for i in xrange(1, len(self.symbols), 2): 65 | yield ' .skip %d' % random.randrange(512, 2048, 4) 66 | yield self.symbols[i] + ':' 67 | yield ' ldr\t\tx0, ={0}'.format(hex(self.branch[i])) 68 | yield ' ret' 69 | -------------------------------------------------------------------------------- /arch/arm64/tests/mkmain: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import random 5 | symbols = sorted(l.strip() for l in sys.stdin if l.strip()) 6 | 7 | print r''' 8 | #include 9 | #include 10 | #include 11 | 12 | void handler(int sig_num, siginfo_t * info, void * ucontext) { 13 | (void) ucontext; 14 | fprintf(stderr, "Received signal %d (%s) at %p.\n", sig_num, strsignal(sig_num), info->si_addr); 15 | exit(0xe); 16 | } 17 | 18 | void install_handler() { 19 | struct sigaction sigact; 20 | sigact.sa_sigaction = handler; 21 | sigact.sa_flags = SA_RESTART | SA_SIGINFO; 22 | if (sigaction(SIGSEGV, &sigact, 0) || sigaction(SIGILL, &sigact, 0)) { 23 | fprintf(stderr, "Error installing signal handler.\n"); 24 | exit(1); 25 | } 26 | } 27 | 28 | ''' 29 | 30 | for symbol in symbols: 31 | print 'unsigned long %s();' % symbol 32 | 33 | print 34 | 35 | print r''' 36 | int main() { 37 | install_handler(); 38 | unsigned long result; 39 | int res = 0; 40 | ''' 41 | 42 | def human_name(s): 43 | return ' '.join(s.split('_')[1:]) 44 | 45 | for symbol in symbols: 46 | print r''' result = {0}(); 47 | if (result) {{ 48 | ++res; 49 | printf("%-32s FAILED: %16lx\n", "{1}", result); 50 | }}'''.format(symbol, human_name(symbol)) 51 | 52 | print r''' printf("Failed tests: %d\n", res); 53 | return res; 54 | }''' -------------------------------------------------------------------------------- /arch/arm64/tests/mktest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import bisect 4 | import sys 5 | import subprocess 6 | import struct 7 | import os 8 | import glob 9 | 10 | from common import TemplateTest 11 | 12 | _modules = [os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] 13 | for test in _modules: 14 | __import__(test) 15 | 16 | if __name__ == '__main__': 17 | adbifiles = [] 18 | baseclassname = TemplateTest.__name__ 19 | with open('adbitest.adbi', 'w') as adbi: 20 | adbi.write('\n'.join(['#binary adbitest','INIT() {}',''])) 21 | for cls in vars()[baseclassname].__subclasses__(): 22 | name = cls.__name__ 23 | print name 24 | tst = cls() 25 | 26 | 27 | if name.startswith('test_'): 28 | name = name[5:] 29 | 30 | with open(name + '.S', 'w') as asm: 31 | tst.generate(asm, adbi) 32 | -------------------------------------------------------------------------------- /arch/arm64/trap.c: -------------------------------------------------------------------------------- 1 | #include "tracepoint/jump.h" 2 | #include "process/process.h" 3 | #include "process/thread.h" 4 | #include "procutil/ptrace.h" 5 | #include "process/linker.h" 6 | 7 | bool thread_trap(thread_t * thread) { 8 | 9 | pt_regs regs; 10 | address_t ip, jump_target; 11 | 12 | if (unlikely(!thread_get_regs(thread, ®s))) { 13 | /* Thread died while reading registers. Consider this case as handled. */ 14 | return true; 15 | } 16 | 17 | ip = regs.pc; 18 | jump_target = jump_get(thread->process, ip); 19 | 20 | debug("Thread %s hit a break at %s.", str_thread(thread), str_address(thread->process, ip)); 21 | 22 | #if 0 /* enable to see full context on each hit */ 23 | dump_thread(thread); 24 | #endif 25 | 26 | if (likely(jump_target)) { 27 | /* Thread hit a tracepoint. Change the PC and let it continue. */ 28 | if (likely(!thread->process->stabilizing)) { 29 | debug("Thread %s jumping to %s.", str_thread(thread), str_address(thread->process, jump_target)); 30 | regs.pc = jump_target; 31 | if (likely(thread_set_regs(thread, ®s))) { 32 | thread_continue_or_stop(thread, 0); 33 | } 34 | } else { 35 | /* The process is currently stabilizing threads. The current thread just hit a tracepoint, but we don't 36 | * change its address to the trampoline, we just leave it stopped. If we continue the thread now, it 37 | * will hit the tracepoint again. */ 38 | info("Thread %s is stabilizing, deferring jump to %s.", str_thread(thread), 39 | str_address(thread->process, jump_target)); 40 | } 41 | return true; 42 | } 43 | 44 | /* Linker breakpoint */ 45 | if (likely(ip == thread->process->linker.bkpt)) { 46 | /* Linker breakpoint */ 47 | linker_notify(thread); 48 | regs.pc = regs.regs[30]; 49 | if (likely(thread_set_regs(thread, ®s))) { 50 | thread_continue_or_stop(thread, 0); 51 | } 52 | return true; 53 | } 54 | 55 | return false; 56 | } 57 | -------------------------------------------------------------------------------- /communication/communication.h: -------------------------------------------------------------------------------- 1 | #ifndef ASYNCIO_H 2 | #define ASYNCIO_H 3 | 4 | bool comm_init(void); 5 | void comm_cleanup(void); 6 | 7 | void comm_handle_io(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /communication/protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOCOL_H 2 | #define PROTOCOL_H 3 | 4 | #include 5 | 6 | typedef packed_struct packet_header_t { 7 | uint32_t type; /* packet type */ 8 | uint32_t seq; /* packet sequence number */ 9 | uint32_t length; /* packet size */ 10 | } packet_header_t; 11 | 12 | typedef struct packet_t { 13 | packet_header_t head; 14 | void * payload; 15 | } packet_t; 16 | 17 | bool protocol_init(); 18 | void protocol_cleanup(); 19 | 20 | packet_t * packet_create(const packet_header_t * head); 21 | void packet_free(packet_t * packet); 22 | 23 | const packet_t * handle_packet(const packet_t * request); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /configuration/state.c: -------------------------------------------------------------------------------- 1 | #include "state.h" 2 | #include "process/process.h" 3 | 4 | static bool state_tracing_val = false; 5 | 6 | bool state_tracing() { 7 | return state_tracing_val; 8 | } 9 | 10 | void state_tracing_set(bool state) { 11 | if (state_tracing_val == state) 12 | return; 13 | if (state) { 14 | process_continue_all(); 15 | } else { 16 | process_stop_all(); 17 | } 18 | state_tracing_val = state; 19 | } 20 | -------------------------------------------------------------------------------- /configuration/state.h: -------------------------------------------------------------------------------- 1 | #ifndef STATE_H_ 2 | #define STATE_H_ 3 | 4 | bool state_tracing(); 5 | void state_tracing_set(bool state); 6 | 7 | #endif /* STATE_H_ */ 8 | -------------------------------------------------------------------------------- /demo/adbi_snprintf/README: -------------------------------------------------------------------------------- 1 | Snprintf implementation for ADBI. 2 | 3 | Unless ADBI IDK tools are mostly independent from toolchain, and cannot take advantege of libc standard library there is need to implement some helper functions. 4 | 5 | Usage: 6 | Make sure ADBICC env variable is set to valid path to gcc. If not: 7 | export ADBICC=/path/to/gcc-4.9/bin/aarch64-linux-android-gcc 8 | 9 | Compile: 10 | mkinj --library adbi_snprintf adbi_snprintf.c 11 | 12 | -------------------------------------------------------------------------------- /demo/binder/README: -------------------------------------------------------------------------------- 1 | This demo will show how to track when processes are using /dev/binder device. The only place where libbinder talks to binder device is function IPCThreadState::talkWithDriver(). This demo will show how to prepare injectable for tracing calls and returns from IPCThreadState::talkWithDriver() function. 2 | 3 | At first we need to create filter file to filter unneeded functions from tracking (autoadbi generates handlers for all procedures in binary by default). Unfortunately ADBI does not suport C++ DWARF information, therefore we need to create file with pattern that will match IPCThreadState::talkWithDriver() symbol name. We can obtain symbol name using readelf and writes it to filter file, but if we need more portable soluion better idea is to prepare regex. Like: 4 | 5 | .*IPCThreadState.*talkWithDriver.* 6 | 7 | Usage: 8 | 9 | Make sure ADBICC env variable is set to valid path to gcc. If not: 10 | export ADBICC=/path/to/gcc-4.9/bin/aarch64-linux-android-gcc 11 | 12 | For this example we need adbi_snprintf library injectable on the device. Refer to ./demo/adbi_snprintf directory. 13 | 14 | 15 | 1. Link system root directory with debugging symbols: 16 | 17 | ln -s $ANDROID/out/target/product/$PRODUCT/symbols 18 | 19 | 2. Generate handlers at begin and end of taklWithDriver function in IPCThreadState class using systrace handler template: 20 | 21 | autoadbi -t systrace -a fns --sysroot ./symbols -f binder.patterns /system/lib64/libbinder.so > generated.adbi 22 | 23 | -t systrace -> Use systrace handler template. This template generates 24 | code that writes to trace_marker on tracepoint hit. 25 | -a fns -> Action: functions (fns) - track procedures begin and end. 26 | Autoadbi will automatically find all procedure epilogs. 27 | --sysroot -> Path to system root directory. 28 | -f binder.patterns -> Filter file. Filter out all symbols/function names that 29 | don't match any pattern from file (file uses Regex patterns). 30 | 31 | 3. Make injectable: 32 | 33 | mkinj --sysroot ./symbols generated.adbi 34 | 35 | 4. Copy all needed files to device 36 | 37 | adb push ./adbi_snpintf.inj /data/ 38 | adb push ./generated.inj /data/ 39 | 40 | 5. Run: 41 | 42 | a) Obtain zygote64 PID 43 | 44 | adb shell ps | grep zygote64 45 | 46 | b) Run adbiserver 47 | 48 | adb forward tcp:9999 tcp:9999 49 | adb shell 50 | # su 51 | # setenforce 0 52 | # /data/adbiserver 53 | 54 | c) Attach to zygote64 55 | 56 | adbi3 57 | # load /data/adbi_snprintf.inj 58 | # load /data/generated.inj 59 | # attach $ZYGOTE_PID 60 | # start 61 | 62 | d) See strace output in tracing_pipe 63 | 64 | adb shell 65 | # cd /d/tracing 66 | # echo 1 > ./tracing_on 67 | # cat ./trace_pipe 68 | ^C 69 | 70 | e) Capture systrace 71 | 72 | systrace.py -t 30 sched 73 | -------------------------------------------------------------------------------- /demo/binder/binder.patterns: -------------------------------------------------------------------------------- 1 | .*IPCThreadState.*talkWithDriver.* 2 | -------------------------------------------------------------------------------- /demo/fibo/README: -------------------------------------------------------------------------------- 1 | Demo shows how easy is creating injectable code. File fibo.adbi contains source code of handler that will be executed when execution flow reaches 4th line of fibo.c file (beginning of fibo procedure). Handler will get value of ``n'' variable and print it to adbilog. 2 | 3 | 1. Compile fibo example: 4 | 5 | /path/to/gcc-4.9/bin/aarch64-linux-android-gcc -pie -fPIC -ggdb3 -o fibo fibo.c 6 | 7 | 2. Compile injectable: 8 | Make sure ADBICC env variable is set to valid path to gcc. If not: 9 | export ADBICC=/path/to/gcc-4.9/bin/aarch64-linux-android-gcc 10 | 11 | a) make injectable: 12 | 13 | mkinj --binary /data/fibo ./fibo.adbi 14 | 15 | 3. Push files to the device 16 | 17 | adb push ./fibo /data/ 18 | adb push ./fibo.inj /data/ 19 | -------------------------------------------------------------------------------- /demo/fibo/fibo.adbi: -------------------------------------------------------------------------------- 1 | # binary ./fibo 2 | 3 | IMPORT(adbi_printf, void, const char * fmt, ...); 4 | 5 | # handler fibo.c:4 6 | 7 | # getvar n 8 | 9 | adbi_printf("fibo!\n"); 10 | adbi_printf("%d\n", n); 11 | 12 | # endhandler 13 | 14 | INIT() {} 15 | -------------------------------------------------------------------------------- /demo/fibo/fibo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int fibo(unsigned int n) { 4 | if (n <= 1) 5 | return n; 6 | else 7 | return fibo(n - 1) + fibo(n - 2); 8 | } 9 | 10 | int main(int argc, char * argv[]) { 11 | if (argc != 2) { 12 | printf("Usage: %s N\n", argv[0]); 13 | } else { 14 | unsigned int n = (unsigned int) atoi(argv[1]); 15 | printf("fibo(%u) = %u\n", n, fibo(n)); 16 | } 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /demo/libc/README: -------------------------------------------------------------------------------- 1 | 2 | Usage: 3 | 4 | Make sure ADBICC env variable is set to valid path to gcc. If not: 5 | export ADBICC=/path/to/gcc-4.9/bin/aarch64-linux-android-gcc 6 | 7 | For this example we need adbi_snprintf library injectable on the device. Refer to ./demo/adbi_snprintf directory. 8 | 9 | 10 | 1. Link system root directory with debugging symbols: 11 | 12 | ln -s $ANDROID/out/target/product/$PRODUCT/symbols 13 | 14 | 2. Generate handlers at svc instructions inside given symbols using systrace handler template: 15 | 16 | autoadbi -t systrace -a insn --sysroot ./symbols -f patterns /system/lib64/libc.so > io.adbi 17 | 18 | -t systrace -> Use systrace handler template. This template generates 19 | code that writes to trace_marker on tracepoint hit. 20 | -a insn -> Action: instruction (insn) - track particular instruction(default: svc). Mark inctuction as begin and instruction after traced one as end. 21 | Autoadbi will automatically find all procedure epilogs. 22 | --sysroot -> Path to system root directory. 23 | -f patterns -> Filter file. Filter out all symbols/function names that 24 | don't match any pattern from file (file uses Regex patterns). 25 | 26 | 3. Make injectable: 27 | 28 | mkinj --sysroot ./symbols io.adbi 29 | 30 | 4. Copy all needed files to device: 31 | 32 | adb push ./adbi_snpintf.inj /data/ 33 | adb push ./io.inj /data/ 34 | 35 | 5. Run: 36 | 37 | a) Obtain zygote64 PID 38 | 39 | adb shell ps | grep zygote64 40 | 41 | b) Run adbiserver: 42 | 43 | adb forward tcp:9999 tcp:9999 44 | adb shell 45 | # su 46 | # setenforce 0 47 | # /data/adbiserver 48 | 49 | c) Attach to zygote64: 50 | 51 | adbi3 52 | # load /data/adbi_snprintf.inj 53 | # load /data/io.inj 54 | # attach $ZYGOTE_PID 55 | # start 56 | 57 | d) See strace output in tracing_pipe: 58 | 59 | adb shell 60 | # cd /d/tracing 61 | # echo 1 > ./tracing_on 62 | # cat ./trace_pipe 63 | ^C 64 | 65 | e) Capture systrace: 66 | 67 | systrace.py -t 30 68 | 69 | or 70 | 71 | systrace.py -t 30 sched 72 | -------------------------------------------------------------------------------- /demo/libc/patterns: -------------------------------------------------------------------------------- 1 | fdopen 2 | fopen 3 | readahead 4 | read 5 | write 6 | pread64 7 | pwrite64 8 | close 9 | ioctl 10 | readv 11 | writev 12 | select 13 | fsync 14 | fdatasync 15 | sync 16 | sendfile 17 | socket 18 | socketpair 19 | bind 20 | connect 21 | listen 22 | accept4 23 | sendto 24 | recvfrom 25 | shutdown 26 | sendmsg 27 | recvmsg 28 | poll 29 | fflush 30 | freopen 31 | openat 32 | open 33 | -------------------------------------------------------------------------------- /demo/openfiles/README: -------------------------------------------------------------------------------- 1 | Demo shows all open and creat calls. Output can be see in adbilog. Handlers are placed at first instruction of open and creat functions. First argument (file path) is taken from x0 register and send via adbi_printf to adbilog. 2 | 3 | Usage: 4 | Make sure ADBICC env variable is set to valid path to gcc. If not: 5 | export ADBICC=/path/to/gcc-4.9/bin/aarch64-linux-android-gcc 6 | 7 | 1. link libc.so library into folder with openfiles.adbi file: 8 | 9 | ln -s $ANDROID/out/target/product/$PRODUCT/symbols/system/lib64/libc.so 10 | 11 | 2. make injectable: 12 | 13 | mkinj --binary /system/lib64/libc.so ./opnfiles.adbi 14 | -------------------------------------------------------------------------------- /demo/openfiles/openfiles.adbi: -------------------------------------------------------------------------------- 1 | /* This injectable inserts tracepoints into the open and creat functions in libc. Both functions are written in 2 | * assembly, so in this case we need to capture the arguments manually. 3 | */ 4 | 5 | #include 6 | 7 | #binary ./libc.so 8 | 9 | IMPORT(adbi_printf, void, const char * fmt, ...); 10 | 11 | /* open */ 12 | #handler open 13 | char * pathname = (char *) get_reg(0); 14 | adbi_printf("opening %s\n", pathname); 15 | #endhandler 16 | 17 | /* creat */ 18 | #handler creat 19 | char * pathname = (char *) get_reg(0); 20 | adbi_printf("creating %s\n", pathname); 21 | #endhandler 22 | 23 | INIT() { 24 | /* nothing to initialize */ 25 | } 26 | -------------------------------------------------------------------------------- /doc/CALLS: -------------------------------------------------------------------------------- 1 | Calling functions form ADBI 2 | --------------------------- 3 | 4 | Sometimes adbiserver needs to force a child process to execute a function. This occurs when an injectable needs to be 5 | initialized or when ADBI needs to allocate memory in the inferior process. 6 | 7 | To make a call in the child process, adbiserver performs the following steps: 8 | 1. First all threads of the process are stopped. 9 | 2. If required, the threads are additionally stabilized. 10 | 3. A random slave thread T is selected -- it will be used to make the function call. 11 | 4. The full context of thread T is stored (all registers are captured and saved). 12 | 5. The PC register of thread T is set to the address of the function -- this directs control to our function. 13 | 6. The LR register of thread T is set to zero -- this makes sure that just after the function finishes, 14 | a segmentation violation occurs (because the function will return to NULL). 15 | 7. Other registers and the stack are prepared according to the ABI -- first 4 arguments are placed in r0-r3, 16 | further arguments are pushed on the stack. 17 | 8. The T thread is continued, adbiserver wait on the thread (waitpid). 18 | 9. When the thread stops, adbiserver checks stop reason. A SIGSEGV signal at PC == 0 is expected. If stop reason 19 | is different, something went wrong. 20 | 10. The result value is captured from r0. 21 | 11. Context of thread T is restored. 22 | 12. All threads are continued. 23 | -------------------------------------------------------------------------------- /idk/adbicache: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import logging 5 | 6 | from cachebuilder import DebugInfo 7 | 8 | __version__ = "0.1" 9 | 10 | if __name__ == '__main__': 11 | parser = argparse.ArgumentParser(description='Create an ADBI symbol cache files from DWARF binaries.') 12 | parser.add_argument('-V', '--version', action='version', 13 | version="%(prog)s (ADBI 3.0 project) " + __version__) 14 | parser.add_argument('input', type=argparse.FileType('rb'), nargs='+', help='Input binary file.') 15 | parser.add_argument('--log', '-l', 16 | type=str, 17 | choices='DEBUG INFO WARNING ERROR CRITICAL'.split(), 18 | default='INFO', help='set verbosity level (default: %(default)s)') 19 | parser.add_argument('-d', '--dump', 20 | action='store_true', 21 | help='Dump SQL code instead of writing a file.') 22 | args = parser.parse_args() 23 | 24 | loglevel = getattr(logging, args.log.upper()) 25 | logging.basicConfig(format='%(levelname)s: %(message)s', level=loglevel) 26 | 27 | for infile in args.input: 28 | debuginfo = DebugInfo(infile) 29 | if args.dump: 30 | conn = debuginfo.cache 31 | for line in conn.iterdump(): 32 | print line 33 | else: 34 | debuginfo.store() 35 | 36 | -------------------------------------------------------------------------------- /idk/cachebuilder/__init__.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sys 3 | 4 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'elftools.zip')) 5 | 6 | from .debuginfo import DebugInfo 7 | -------------------------------------------------------------------------------- /idk/cachebuilder/cfi.py: -------------------------------------------------------------------------------- 1 | from base64 import b64encode 2 | from collections import namedtuple 3 | import logging 4 | 5 | from elftools.dwarf.callframe import FDE 6 | 7 | from common.leb128 import LEB, SLEB 8 | 9 | CallFrameInfoEntry = namedtuple('CallFrameInfoEntry', 'low high expr') 10 | 11 | class CallFrameInfo: 12 | def __init__(self, debug_info): 13 | self.debug_info = debug_info 14 | 15 | def iter_entries(): 16 | if not self.debug_info.dwarf.has_CFI(): 17 | logging.warn('ELF has no call frame information.') 18 | return 19 | 20 | for fde in self.debug_info.dwarf.CFI_entries(): 21 | 22 | if not isinstance(fde, FDE): 23 | continue 24 | 25 | low = fde.header.initial_location 26 | high = low + fde.header.address_range 27 | 28 | invalid = False 29 | decoded = fde.get_decoded().table 30 | for n, each in enumerate(decoded, 0): 31 | try: 32 | entry_low = debug_info.addr2fo(each['pc']) 33 | entry_high = debug_info.addr2fo(high if n >= len(decoded) - 1 else decoded[n + 1]['pc']) 34 | except ValueError: 35 | invalid = True 36 | continue 37 | 38 | cfa_rule = each['cfa'] 39 | if cfa_rule.expr is not None: 40 | # CFA is a regular DWARF expressions 41 | expr = cfa_rule.expr 42 | else: 43 | assert cfa_rule.reg is not None 44 | # CFA is a register + offset -- convert it to a DWARF expression 45 | expr = bytearray([0x92]) # DW_OP_bregx 46 | expr += LEB.encode(cfa_rule.reg) # Register index 47 | expr += SLEB.encode(cfa_rule.offset) # Offset from register 48 | yield CallFrameInfoEntry(entry_low, entry_high, b64encode(expr)) 49 | 50 | if invalid: 51 | logging.warn('Invalid call frame information entry encountered in FDE at %#x.', fde.offset) 52 | 53 | self.entries = list(iter_entries()) 54 | 55 | def store(self, conn): 56 | logging.debug('Storing %i call frame information entries.', len(self.entries)) 57 | query = '''insert into cfi (lo, hi, expr) values (?, ?, ?)''' 58 | conn.executemany(query, self.entries) 59 | conn.commit() -------------------------------------------------------------------------------- /idk/cachebuilder/insnset.py: -------------------------------------------------------------------------------- 1 | from elftools.elf.sections import SymbolTableSection 2 | 3 | from common.enums import InsnKinds 4 | 5 | class InsnSet: 6 | def __init__(self, debug_info): 7 | 8 | def get_kind(sym): 9 | if sym.name.startswith(('$x', '__dl_$x')): 10 | return InsnKinds.arm64 11 | elif sym.name.startswith(('$a', '__dl_$a')): 12 | return InsnKinds.arm 13 | elif sym.name.startswith(('$t', '__dl_$t')): 14 | return InsnKinds.thumb 15 | else: 16 | return InsnKinds.nocode 17 | 18 | # Symbol sections 19 | symsect_iter = (section 20 | for section in debug_info.elf.iter_sections() 21 | if isinstance(section, SymbolTableSection)) 22 | 23 | # Symbols 24 | symbol_iter = (symbol 25 | for section in symsect_iter 26 | for symbol in section.iter_symbols()) 27 | 28 | # Mapping symbols 29 | mapsymbol_iter = (symbol 30 | for symbol in symbol_iter 31 | if symbol.name.startswith(('$x', '$a', '$t', '$d')) 32 | # sometimes linker has all symbols in .symtab beginning with ``__dl_'' 33 | or symbol.name.startswith(('__dl_$x', '__dl_$a', '__dl_$t', '__dl_$d'))) 34 | 35 | def iter_mapping(): 36 | for symbol in mapsymbol_iter: 37 | try: 38 | addr = debug_info.addr2fo(symbol.entry.st_value) 39 | kind = get_kind(symbol) 40 | yield addr, kind 41 | except ValueError: 42 | pass 43 | 44 | self.mapping = list(iter_mapping()) 45 | 46 | 47 | def store(self, conn): 48 | conn.executemany('insert into insnset(addr, kind) values (?, ?)', self.mapping) 49 | conn.commit() 50 | 51 | 52 | -------------------------------------------------------------------------------- /idk/cachebuilder/lines.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | class Lines: 4 | def __init__(self, debuginfo): 5 | def iter_lines(): 6 | for compilation_unit in debuginfo.dwarf.iter_CUs(): 7 | lineprog = debuginfo.dwarf.line_program_for_CU(compilation_unit) 8 | for entry in lineprog.get_entries(): 9 | if (entry.state is None) or (entry.state.end_sequence): 10 | continue 11 | 12 | if not entry.state.is_stmt: 13 | continue 14 | 15 | filename = debuginfo.locations.get_source_file(compilation_unit, entry.state.file) 16 | line = entry.state.line 17 | col = entry.state.column 18 | try: 19 | addr = debuginfo.addr2fo(entry.state.address) 20 | except ValueError: 21 | # line (probably) optimized out 22 | logging.warn('Location %s:%i:%i is mapped to an invalid address %#x (optimized out?).', 23 | filename, line, col, entry.state.address) 24 | addr = None 25 | 26 | loc_id = debuginfo.locations.insert_flc(filename, line, col) 27 | 28 | yield addr, loc_id 29 | 30 | self.lines = list(iter_lines()) 31 | 32 | 33 | def store(self, conn): 34 | logging.debug('Storing %i line to address mapping entries.', len(self.lines)) 35 | 36 | query = 'insert into lines values (?, ?)' 37 | items = ((addr, loc_id) for addr, loc_id in self.lines) 38 | conn.executemany(query, items) 39 | 40 | conn.commit() -------------------------------------------------------------------------------- /idk/cachebuilder/sections.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | import logging 3 | from elftools.elf.constants import SH_FLAGS 4 | 5 | Section = namedtuple('Section', 'id name type addr offset size flags') 6 | 7 | class Sections(object): 8 | def __init__(self, debuginfo): 9 | self.debuginfo = debuginfo 10 | 11 | def iter_sections(): 12 | # omit first section - it is always null section 13 | for idx in range(1, self.debuginfo.elf.num_sections()): 14 | section = self.debuginfo.elf.get_section(idx) 15 | h = section.header 16 | yield Section(idx, section.name, h['sh_type'], h['sh_addr'], h['sh_offset'], h['sh_size'], h['sh_flags']) 17 | 18 | self.sections = list(iter_sections()) 19 | 20 | def addr2fo(self, addr): 21 | '''Convert given virtual address to file offset.''' 22 | for section in [s for s in self.sections if s.flags & SH_FLAGS.SHF_ALLOC]: 23 | lo = section.addr 24 | hi = lo + section.size 25 | if lo <= addr < hi: 26 | offset = addr - lo 27 | return section.offset + offset 28 | raise ValueError('Address %x is invalid.' % addr) 29 | 30 | def store(self, conn): 31 | logging.debug('Storing ELF sections') 32 | query = 'insert into sections(id, name, type, addr, offset, size, flags) values (?, ?, ?, ?, ?, ?, ?)' 33 | items = ((section.id, section.name, section.type, section.addr, section.offset, section.size, section.flags) 34 | for section in self.sections ) 35 | conn.executemany(query, items) 36 | conn.commit() -------------------------------------------------------------------------------- /idk/cachebuilder/symbols.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | from elftools.elf.sections import SymbolTableSection 3 | import itertools 4 | import logging 5 | 6 | 7 | Symbol = namedtuple('Symbol', 'id name value size bind type visibility shndx') 8 | 9 | class Symbols(object): 10 | def __init__(self, debuginfo): 11 | self.debuginfo = debuginfo 12 | self.id_gen = itertools.count() 13 | 14 | # Symbol sections 15 | symsect_iter = (section 16 | for section in debuginfo.elf.iter_sections() 17 | if isinstance(section, SymbolTableSection)) 18 | 19 | # Symbols 20 | symbol_iter = (symbol 21 | for section in symsect_iter 22 | for symbol in section.iter_symbols() 23 | if not symbol.name.startswith(('$x', '$a', '$t', '$d')) 24 | # sometimes linker has all symbols in .symtab beginning with ``__dl_'' 25 | and not symbol.name.startswith(('__dl_$x', '__dl_$a', '__dl_$t', '__dl_$d'))) 26 | 27 | def iter_symbols(): 28 | for symbol in symbol_iter: 29 | e = symbol.entry 30 | yield Symbol(self.id_gen.next(), symbol.name, 31 | e.st_value, e.st_size, e.st_info.bind, e.st_info.type, e.st_other.visibility, e.st_shndx) 32 | 33 | self.symbols = list(iter_symbols()) 34 | 35 | def store(self, conn): 36 | logging.debug('Storing %i symbols' % len(self.symbols)) 37 | query = 'insert into symbols(id, name, value, size, bind, type, vis, shndx) values (?, ?, ?, ?, ?, ?, ?, ?)' 38 | items = ((symbol.id, symbol.name, symbol.value, symbol.size, symbol.bind, symbol.type, symbol.visibility, symbol.shndx) 39 | for symbol in self.symbols) 40 | conn.executemany(query, items) 41 | conn.commit() -------------------------------------------------------------------------------- /idk/cachereader/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samsung/ADBI/3e424c45386b0a36c57211da819021cb1929775a/idk/cachereader/__init__.py -------------------------------------------------------------------------------- /idk/cachereader/base.py: -------------------------------------------------------------------------------- 1 | class BinaryElementBase(object): 2 | def __init__(self, elf): 3 | self.elf = elf 4 | if self.elf: 5 | self.query_db = elf.query_db 6 | self.query_db_one = elf.query_db_one -------------------------------------------------------------------------------- /idk/cachereader/cfa.py: -------------------------------------------------------------------------------- 1 | from .base import BinaryElementBase 2 | from dwexpr import eval_DWARF_expr 3 | 4 | from base64 import b64decode 5 | 6 | class CallFrameAddress(BinaryElementBase): 7 | 8 | def get_expression_code(self, addr): 9 | query = '''select expr from cfi where lo <= ? and ? < hi limit 1''' 10 | ret = self.query_db_one(query, addr, addr) 11 | if ret is None: 12 | raise KeyError 13 | else: 14 | return b64decode(ret) 15 | 16 | def get_expression(self, addr): 17 | return eval_DWARF_expr(self.get_expression_code(addr)) 18 | 19 | def __getitem__(self, addr): 20 | return self.get_expression(addr) 21 | 22 | -------------------------------------------------------------------------------- /idk/cachereader/datatype/__init__.py: -------------------------------------------------------------------------------- 1 | from .create import create 2 | -------------------------------------------------------------------------------- /idk/cachereader/datatype/create.py: -------------------------------------------------------------------------------- 1 | from common.enums import TypeKinds 2 | 3 | from .builtin import SignedIntType, UnsignedIntType, SignedCharType, UnsignedCharType, FloatType, BooleanType 4 | from .compound import StructType, ClassType, UnionType 5 | from .datatype import UnsupportedType 6 | from .enum import EnumType 7 | from .indirect import ConstType, PointerType, ReferenceType, RightReferenceType, VolatileType, RestrictType, ArrayType 8 | from .typedef import TypedefType 9 | 10 | 11 | MAPPING = { 12 | TypeKinds.int : SignedIntType, 13 | TypeKinds.uint : UnsignedIntType, 14 | TypeKinds.char : SignedCharType, 15 | TypeKinds.uchar : UnsignedCharType, 16 | TypeKinds.float : FloatType, 17 | TypeKinds.bool : BooleanType, 18 | 19 | TypeKinds.const : ConstType, 20 | TypeKinds.ptr : PointerType, 21 | TypeKinds.ref : ReferenceType, 22 | TypeKinds.rref : RightReferenceType, 23 | TypeKinds.volatile : VolatileType, 24 | TypeKinds.restrict : RestrictType, 25 | TypeKinds.array : ArrayType, 26 | 27 | TypeKinds.struct: StructType, 28 | TypeKinds.cls: ClassType, 29 | TypeKinds.union: UnionType, 30 | TypeKinds.enum: EnumType, 31 | 32 | TypeKinds.typedef: TypedefType, 33 | } 34 | 35 | def create(elf, tid, kind, name, bit_size, inner_id, loc_id): 36 | cls = MAPPING.get(kind, UnsupportedType) 37 | return cls(elf, tid, kind, name, bit_size, inner_id, loc_id) 38 | -------------------------------------------------------------------------------- /idk/cachereader/datatype/enum.py: -------------------------------------------------------------------------------- 1 | from ..C import INDENT 2 | from .datatype import DataType, TypeInfo 3 | from common.deco import cachedprop 4 | 5 | 6 | class EnumType(DataType): 7 | 8 | def _get_is_scalar(self): 9 | return True 10 | 11 | class Enumerator(TypeInfo): 12 | def __init__(self, elf, eid): 13 | query = 'select parent, name, value, loc from enumerators where id=?' 14 | parent_id, name, self.value, loc_id = elf.query_db_one(query, eid) 15 | TypeInfo.__init__(self, elf, parent_id, name, loc_id) 16 | 17 | def define_enumerators(self): 18 | if self.enumerators: 19 | nl = max(len(enumeration.name) for enumeration in self.enumerators) 20 | xl = max(len(hex(enumeration.value)) for enumeration in self.enumerators) - 2 21 | dl = max(len(str(enumeration.value)) for enumeration in self.enumerators) 22 | for enumeration in self.enumerators: 23 | n = enumeration.name 24 | v = enumeration.value 25 | yield '%-*s = 0x%0*x, /* == %*i */' % (nl, n, xl, v, dl, v) 26 | else: 27 | yield '/* no enumerators */' 28 | 29 | @cachedprop 30 | def enumerators(self): 31 | return [self.Enumerator(self.elf, eid) for eid in self.query_db('select id from enumerators where parent=?', self.tid)] 32 | 33 | 34 | def _define_var_type(self): 35 | if self.is_anonymous: 36 | yield 'enum {' 37 | for line in self.define_enumerators(): 38 | yield INDENT + line 39 | yield '}' 40 | else: 41 | yield 'enum %s' % self.codename 42 | 43 | 44 | def define(self): 45 | if not self.is_anonymous: 46 | yield 'enum %s {' % self.codename 47 | for line in self.define_enumerators(): 48 | yield INDENT + line 49 | yield '};' 50 | else: 51 | # Type anonymous, no need to define 52 | pass 53 | 54 | def __str__(self): 55 | return 'enum %s' % self.safename -------------------------------------------------------------------------------- /idk/cachereader/datatype/typedef.py: -------------------------------------------------------------------------------- 1 | from .datatype import DataType 2 | from .compound import CompoundType 3 | from .enum import EnumType 4 | 5 | 6 | class TypedefType(DataType): 7 | def __init__(self, elf, tid, kind, name, byte_size, inner_id, loc_id): 8 | DataType.__init__(self, elf, tid, kind, name, byte_size, inner_id, loc_id) 9 | self.byte_size = self.byte_size or self.inner.byte_size 10 | 11 | @property 12 | def inner(self): 13 | if self.inner_id is not None: 14 | return self.elf.types[self.inner_id] 15 | 16 | def _get_is_scalar(self): 17 | # Typedefs are special -- they are simple aliases of other types. They are scalar 18 | # if the inner type is scalar too. 19 | return self.inner.is_scalar 20 | 21 | def get_soft_requirements(self): 22 | if self.inner.is_anonymous: 23 | return self.inner.soft_requirements 24 | else: 25 | return set() 26 | 27 | def get_hard_requirements(self): 28 | if self.inner.is_anonymous: 29 | return self.inner.hard_requirements 30 | else: 31 | return set([self.inner]) 32 | 33 | def declare(self): 34 | if self.inner.is_anonymous: 35 | raise NotImplementedError 36 | 37 | if not isinstance(self.inner, (CompoundType, EnumType)): 38 | raise NotImplementedError 39 | 40 | return self.define() 41 | 42 | def define(self): 43 | spec = list(self.inner.define_var(self.name)) 44 | spec[0] = 'typedef ' + spec[0] 45 | for line in spec: 46 | yield line 47 | 48 | def _get_printf_pattern(self): 49 | return self.inner.printf_pattern 50 | 51 | def get_printf_elements(self, name): 52 | return self.inner.get_printf_elements(name) 53 | 54 | def __str__(self): 55 | return 'typedef %s' % self.safename -------------------------------------------------------------------------------- /idk/cachereader/files.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | from base import BinaryElementBase 4 | 5 | 6 | class Files(BinaryElementBase): 7 | 8 | def __init__(self, elf): 9 | BinaryElementBase.__init__(self, elf) 10 | self.files = set(self.query_db('select distinct path from files')) 11 | 12 | self.prefix = os.path.commonprefix([x for x in self.files if not x.startswith('/tmp/')]) 13 | idx = self.prefix.rfind('/') 14 | if idx > 0: 15 | self.prefix = self.prefix[:idx + 1] 16 | else: 17 | self.prefix = '' 18 | 19 | def unique_end(path): 20 | conflicts = set(each for each in self.files if each != path) 21 | 22 | slashpos = None 23 | while True: 24 | slashpos = path.rfind(os.path.sep, None, slashpos) 25 | if slashpos == -1: 26 | return path 27 | 28 | candidate = path[slashpos:] 29 | conflicts = set(each for each in conflicts if each.endswith(candidate)) 30 | if not conflicts: 31 | return candidate[1:] 32 | 33 | self.shortfiles = { each:unique_end(each) for each in self.files } 34 | 35 | def __iter__(self): 36 | return iter(self.files) 37 | 38 | def simplify(self, path): 39 | if path in self.files: 40 | return self.shortfiles[path] 41 | else: 42 | if path.startswith(self.prefix): 43 | return path[len(self.prefix):] 44 | else: 45 | return path 46 | 47 | def expand(self, path): 48 | norm = os.path.normpath(path) 49 | 50 | if os.path.isabs(norm): 51 | if norm not in self.files: 52 | raise ValueError('Unknown source file: %s.' % norm) 53 | return norm 54 | 55 | norm = '/' + norm 56 | 57 | matches = [x for x in self.files if x.endswith(norm)] 58 | 59 | if len(matches) == 1: 60 | return matches.pop() 61 | elif matches: 62 | raise ValueError('Ambiguous source file: %s.' % path) 63 | else: 64 | raise ValueError('No source file matches: %s.' % path) 65 | 66 | -------------------------------------------------------------------------------- /idk/cachereader/framepointers.py: -------------------------------------------------------------------------------- 1 | from base64 import b64decode 2 | 3 | from .base import BinaryElementBase 4 | from common.deco import cachedfn 5 | from dwexpr import eval_DWARF_expr 6 | 7 | class Framepointers(BinaryElementBase): 8 | 9 | @cachedfn 10 | def __getitem__(self, addr): 11 | # Search by frame pointer range 12 | query = '''select framepointers.expr from framepointers 13 | where lo <= ? and ? < hi''' 14 | ret = self.query_db_one(query, addr, addr) 15 | if ret is not None: 16 | return b64decode(ret) 17 | 18 | # Search by function 19 | query = '''select framepointers.expr 20 | from framepointers join functions 21 | on framepointers.func = functions.id 22 | where functions.lo <= ? and ? < functions.hi and framepointers.lo is null''' 23 | ret = self.query_db_one(query, addr, addr) 24 | if ret is not None: 25 | return b64decode(ret) 26 | 27 | # Failed 28 | raise KeyError 29 | 30 | 31 | def getframe(self, addr): 32 | return eval_DWARF_expr(self[addr]) 33 | -------------------------------------------------------------------------------- /idk/cachereader/function.py: -------------------------------------------------------------------------------- 1 | from base64 import b64decode 2 | 3 | from .base import BinaryElementBase 4 | from common.deco import cachedprop, cachedfn 5 | from dwexpr import eval_DWARF_expr 6 | 7 | class Function(BinaryElementBase): 8 | def __init__(self, elf, idx, name, lo, hi, loc): 9 | BinaryElementBase.__init__(self, elf) 10 | self.name = name 11 | self.lo = lo 12 | self.hi = hi 13 | self.loc_id = loc 14 | self.idx = idx 15 | 16 | @property 17 | def location(self): 18 | if self.loc_id is not None: 19 | return self.elf.locations[self.loc_id] 20 | 21 | @cachedprop 22 | def expressions(self): 23 | return list(self.query_db('select lo, hi, expr from framepointers where func=?', self.idx)) 24 | 25 | def get_expression(self, addr): 26 | for low, high, expr in self.expressions: 27 | if low is None: 28 | return b64decode(expr) 29 | else: 30 | if low <= addr < high: 31 | return b64decode(expr) 32 | 33 | def getframe(self, addr): 34 | return eval_DWARF_expr(self.get_expression(addr)) 35 | 36 | def iter_locations(self): 37 | '''Yield address-location pairs inside the function.''' 38 | return self.elf.lines.iter_locations(self.lo, self.hi) 39 | 40 | @cachedprop 41 | def first_insn(self): 42 | '''Address of first instruction after the preamble. 43 | 44 | The address is evaluated heuristically. It is the second address inside the function, for 45 | which a line information entry exists. 46 | ''' 47 | for n, (addr, dummy) in enumerate(self.iter_locations(), 1): 48 | if n >= 2: 49 | return addr 50 | return self.lo 51 | 52 | @cachedprop 53 | def params(self): 54 | '''Return a list of parameter variables.''' 55 | query = 'select var from params where func=? order by idx' 56 | return [self.elf.variables[each] for each in self.query_db(query, self.idx)] 57 | 58 | 59 | class Functions(BinaryElementBase): 60 | 61 | @cachedfn 62 | def __getitem__(self, idx): 63 | query = 'select name, lo, hi, loc from functions where id = ?' 64 | name, lo, hi, loc = self.query_db_one(query, idx) 65 | return Function(self.elf, idx, name, lo, hi, loc) 66 | 67 | 68 | def __iter__(self): 69 | query = 'select id from functions' 70 | for idx in self.query_db(query): 71 | yield self[idx] 72 | 73 | 74 | -------------------------------------------------------------------------------- /idk/cachereader/insnset.py: -------------------------------------------------------------------------------- 1 | from .base import BinaryElementBase 2 | 3 | from common.deco import rangecachedfn 4 | from common.enums import InsnKinds 5 | 6 | 7 | class InsnSet(BinaryElementBase): 8 | def __init__(self, elf): 9 | BinaryElementBase.__init__(self, elf) 10 | 11 | @rangecachedfn 12 | def get_kind_range(self, addr): 13 | res = self.query_db_one('select kind, addr from insnset where addr <= ? order by addr desc limit 1', addr) 14 | hi = self.query_db_one('select addr from insnset where ? < addr order by addr asc limit 1', addr) 15 | 16 | kind = res[0] if res else InsnKinds.nocode 17 | lo = res[1] if res else 0 18 | hi = hi if hi else addr + 32 19 | 20 | return kind, lo, hi 21 | 22 | def get_kind(self, addr): 23 | res, _, _ = self.get_kind_range(addr) 24 | return res 25 | 26 | def __getitem__(self, idx): 27 | return self.get_kind(idx) -------------------------------------------------------------------------------- /idk/cachereader/lines.py: -------------------------------------------------------------------------------- 1 | from base import BinaryElementBase 2 | 3 | class Lines(BinaryElementBase): 4 | def __init__(self, elf): 5 | BinaryElementBase.__init__(self, elf) 6 | 7 | def iter_locations(self, low, high): 8 | '''Yield address-location pairs in the given address range.''' 9 | query = '''select addr, loc from lines where ? <= addr and addr < ? order by addr''' 10 | for addr, lid in self.query_db(query, low, high): 11 | yield addr, self.elf.locations[lid] 12 | 13 | def get_location(self, addr): 14 | '''Get the location mapped to the given address.''' 15 | query = 'select loc from lines where addr = ?' 16 | return self.elf.locations[self.query_db(query, addr)] 17 | 18 | -------------------------------------------------------------------------------- /idk/cachereader/location.py: -------------------------------------------------------------------------------- 1 | from base import BinaryElementBase 2 | 3 | 4 | class Location(BinaryElementBase): 5 | def __init__(self, elf, file, line, col): 6 | BinaryElementBase.__init__(self, elf) 7 | self.trio = (file, line, col) 8 | 9 | @property 10 | def file(self): 11 | return self.trio[0] 12 | 13 | @property 14 | def sfile(self): 15 | if self.file: 16 | return self.elf.files.simplify(self.file) 17 | 18 | @property 19 | def line(self): 20 | return self.trio[1] 21 | 22 | @property 23 | def col(self): 24 | return self.trio[2] 25 | 26 | def __hash__(self): 27 | return hash(self.file) ^ self.line ^ self.col 28 | 29 | def __cmp__(self, other): 30 | return cmp(self.trio, other.trio) 31 | 32 | def __getitem__(self, idx): 33 | return self.trio[idx] 34 | 35 | def __str__(self): 36 | coords = [str(x) for x in (self.sfile, self.line, self.col) if x] 37 | if coords: 38 | return ':'.join(coords) 39 | else: 40 | return '???' 41 | 42 | UndefinedLocation = Location(None, None, None, None) 43 | 44 | 45 | class Locations(BinaryElementBase): 46 | def __getitem__(self, idx): 47 | query = '''select path, line, col 48 | from locations join files 49 | on files.id = locations.file 50 | where locations.id = ? 51 | limit 1''' 52 | q = self.query_db(query, idx) 53 | for file, line, col in q: 54 | return Location(self.elf, file, line, col) 55 | raise KeyError 56 | 57 | -------------------------------------------------------------------------------- /idk/cachereader/symbols.py: -------------------------------------------------------------------------------- 1 | from cachereader.base import BinaryElementBase 2 | from common.deco import cachedfn 3 | 4 | 5 | class Symbol(BinaryElementBase): 6 | def __init__(self, elf, idx, name, value, size, bind, stype, vis, shndx): 7 | BinaryElementBase.__init__(self, elf) 8 | self.idx = idx 9 | self.name = name 10 | self.value = value 11 | self.size = size 12 | self.bind = bind 13 | self.type = stype 14 | self.visibility = vis 15 | self.shndx = shndx 16 | 17 | class Symbols(BinaryElementBase): 18 | 19 | @cachedfn 20 | def __getitem__(self, idx): 21 | query = 'select name, value, size, bind, type, vis, shndx from symbols where id = ?' 22 | name, value, size, bind, stype, vis, shndx = self.query_db_one(query, idx) 23 | return Symbol(self.elf, idx, name, value, size, bind, stype, vis, shndx) 24 | 25 | def __iter__(self): 26 | query = 'select id from symbols' 27 | for idx in self.query_db(query): 28 | yield self[idx] -------------------------------------------------------------------------------- /idk/cachereader/types.py: -------------------------------------------------------------------------------- 1 | from base import BinaryElementBase 2 | from common.deco import cachedfn, cachedprop 3 | import datatype 4 | 5 | 6 | class Types(BinaryElementBase): 7 | 8 | def __init__(self, elf): 9 | BinaryElementBase.__init__(self, elf) 10 | 11 | @cachedfn 12 | def __getitem__(self, idx): 13 | try: 14 | query = 'select kind, name, bytes, inner, loc from types where id=?' 15 | kind, name, byte_size, inner_id, loc_id = self.query_db_one(query, idx) 16 | return datatype.create(self.elf, idx, kind, name, byte_size, inner_id, loc_id) 17 | except ValueError: 18 | raise KeyError 19 | 20 | @cachedprop 21 | def names(self): 22 | return set([str(each) for each in self if not each.is_anonymous]) 23 | 24 | def __iter__(self): 25 | for tid in self.query_db('select id from types'): 26 | yield self[tid] 27 | 28 | def get_by_name(self, name): 29 | return set(each for each in self if each.name == name or str(each) == name) 30 | 31 | -------------------------------------------------------------------------------- /idk/common/__init__.py: -------------------------------------------------------------------------------- 1 | import deco 2 | import mixin -------------------------------------------------------------------------------- /idk/common/deco.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | def cachedprop(fn): 5 | '''Decorator which creates a cached property.''' 6 | 7 | @wraps(fn) 8 | def get(self): 9 | cache_name = '__' + fn.__name__ + '__cache' 10 | try: 11 | return self.__dict__[cache_name] 12 | except KeyError: 13 | ret = fn(self) 14 | self.__dict__[cache_name] = ret 15 | return ret 16 | 17 | return property(get) 18 | 19 | def rangecachedfn(fn): 20 | '''Decorator which creates a range memoized function. Decorator speeds up functions that response 21 | depends on numeric parameter and is constant in some ranges of this parameter. Decorated function must have 22 | numeric parameter as second positional parameter. Decorated function must return response, lower boundary 23 | and high boundary. Response will be cached for all function calls with second parameter in returned range 24 | and the same other parameters. Keyword arguments are not supported.''' 25 | memo = {} 26 | 27 | @wraps(fn) 28 | def wrapper(*args): 29 | try: 30 | return memo[args], None, None 31 | except KeyError: 32 | rv, lo, hi = fn(*args) 33 | if hi: 34 | for i in range(lo, hi): 35 | newargs = list(args) 36 | newargs[1] = i 37 | memo[tuple(newargs)] = rv 38 | else: 39 | memo[args] = rv 40 | 41 | return rv, lo, hi 42 | 43 | return wrapper 44 | 45 | def cachedfn(fn): 46 | '''Decorator which creates a memoized function.''' 47 | memo = {} 48 | 49 | @wraps(fn) 50 | def wrapper(*args): 51 | try: 52 | return memo[args] 53 | except KeyError: 54 | #print 'Calling %s(%s)' % (fn.__name__, ', '.join([str(x) for x in args])) 55 | rv = fn(*args) 56 | memo[args] = rv 57 | return rv 58 | 59 | return wrapper 60 | 61 | 62 | def singleton(cls): 63 | '''Convert the given into a singleton. 64 | 65 | This function is ment to be used as a decorator (which should be applied to 66 | classes, e.g.: 67 | 68 | @singleton 69 | class Foo: 70 | pass 71 | 72 | After this, the class can be called (as if an constructor was called), but 73 | the call will always return the same instance, e.g.: 74 | 75 | a = Foo() 76 | b = Foo() 77 | assert a is b 78 | assert id(a) == id(b) 79 | 80 | Implementation taken from PEP 318 examples. 81 | ''' 82 | instances = {} 83 | def getinstance(): 84 | if cls not in instances: 85 | instances[cls] = cls() 86 | return instances[cls] 87 | return getinstance 88 | 89 | -------------------------------------------------------------------------------- /idk/common/enums.py: -------------------------------------------------------------------------------- 1 | 2 | class TypeKinds(object): 3 | # special unsupported type 4 | unsupported = 0 5 | 6 | # base types 7 | int = 0x01 8 | uint = 0x02 9 | char = 0x03 10 | uchar = 0x04 11 | float = 0x05 12 | bool = 0x06 13 | 14 | # modifiers 15 | const = 0x10 16 | packed = 0x11 17 | ptr = 0x12 18 | ref = 0x13 19 | rref = 0x14 20 | shared = 0x15 21 | volatile = 0x16 22 | restrict = 0x17 23 | array = 0x18 24 | 25 | # compound 26 | struct = 0x20 27 | cls = 0x21 28 | union = 0x22 29 | 30 | # other special types 31 | typedef = 0x30 32 | enum = 0x31 33 | function = 0x32 34 | 35 | # various kinds not present in C/C++ or not generated by GCC 36 | condition = 0x40 37 | string = 0x41 38 | set = 0x42 39 | subrange = 0x43 40 | memberptr = 0x44 41 | file = 0x45 42 | template_alias = 0x46 43 | 44 | 45 | class InsnKinds(object): 46 | nocode = 0 47 | arm64 = 8 48 | arm = 4 49 | thumb = 2 50 | -------------------------------------------------------------------------------- /idk/common/leb128.py: -------------------------------------------------------------------------------- 1 | class BaseLEB(object): 2 | 3 | SIGNED = None 4 | 5 | @classmethod 6 | def decode(cls, stream): 7 | '''Decode a LEB128 or SLEB128 value from stream and return it. 8 | 9 | The stream must implement the buffer interface. The method only consumes as much data as required. 10 | If there is not enough data to decode a valid number, ValueError is risen. 11 | 12 | If signed evaluates to true, a LEB number is decoded. Otherwise, a SLEB number is decoded.''' 13 | result = 0 14 | shift = 0 15 | while True: 16 | b = stream.read(1) 17 | if not b: 18 | raise ValueError('unexpected end of data') 19 | b = ord(b) 20 | result |= (b & 0x7f) << shift 21 | shift += 7 22 | if b & 0x80 == 0: 23 | break 24 | 25 | if cls.SIGNED and (b & 0x40): 26 | result |= -(1 << shift) 27 | 28 | return result 29 | 30 | @classmethod 31 | def encode_iter(cls, value): 32 | '''Encode the given value as a LEB128 or SLEB128 and yield its bytes. 33 | 34 | If signed evaluates to true, a LEB number is encoded. Otherwise, a SLEB number is encoded.''' 35 | 36 | if value < 0 and not cls.SIGNED: 37 | raise ValueError 38 | 39 | while True: 40 | seven = value & 0x7f 41 | value >>= 7 42 | 43 | if cls.SIGNED: 44 | last = (value == 0 and not (seven & 0x40)) or ((value == -1) and (seven & 0x40)) 45 | else: 46 | last = (value == 0) 47 | 48 | yield seven | (0x80 if not last else 0) 49 | if last: 50 | break 51 | 52 | @classmethod 53 | def encode(cls, value): 54 | '''Encode the given value as a LEB128 or SLEB128 and return it as a bytearray.''' 55 | return bytearray(cls.encode_iter(value)) 56 | 57 | 58 | class LEB(BaseLEB): 59 | '''Class for encoding and decoding LEB128 numbers.''' 60 | SIGNED = False 61 | 62 | 63 | class SLEB(BaseLEB): 64 | '''Class for encoding and decoding SLEB128 numbers.''' 65 | SIGNED = True 66 | -------------------------------------------------------------------------------- /idk/common/mixin.py: -------------------------------------------------------------------------------- 1 | class EqualityMixin(object): 2 | '''Helper base class for easy equality and inequality implementation. ''' 3 | 4 | def _clseq(self, other): 5 | '''Check if other is an instance of the same class as self.''' 6 | return isinstance(other, self.__class__) 7 | 8 | def __eq__(self, other): 9 | raise NotImplementedError('__eq__ not implemented in class %s' % self.__class__.__name__) 10 | 11 | def __ne__(self, other): 12 | return not (self == other) -------------------------------------------------------------------------------- /idk/common/output.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | 3 | 4 | try: 5 | from fabulous.color import red, yellow, bold, black 6 | except ImportError: 7 | identity = lambda x: x 8 | red = yellow = bold = black = identity 9 | 10 | 11 | def table(data, head=None, align=None, indent=2, sep=4): 12 | '''Print a table.''' 13 | rows = [[str(e) for e in row] for row in data] 14 | if not rows: 15 | return 16 | 17 | colsc = len(rows[0]) 18 | sep = ' ' * sep 19 | 20 | if not align: 21 | align = '>' * colsc 22 | 23 | if head: 24 | rows = [head] + rows 25 | width = [max(len(row[column]) for row in rows) for column in xrange(colsc)] 26 | 27 | fmt = (' ' * indent) + sep.join('{:%s%i}' % (align[i], width[i]) for i in xrange(colsc)) 28 | 29 | for row in rows: 30 | vals = [str(e) for e in row] 31 | print fmt.format(*vals) 32 | 33 | 34 | def annotated_source(sourcefile, marks=None, annotations=None, context=3, mark='*'): 35 | 36 | marks = marks or [] 37 | annotations = annotations or {} 38 | 39 | interresting = set(marks) | set(annotations) 40 | printed = [range(n - context, n + context + 1) for n in interresting] 41 | printed = set(sum(printed, [])) 42 | 43 | lastprinted = 0 44 | with codecs.open(sourcefile, 'r', 'utf-8', 'replace') as f: 45 | print yellow(sourcefile) 46 | for n, line in enumerate(f, 1): 47 | if n in printed: 48 | m = red(mark if n in marks else ' ' * len(mark)) 49 | c = line.rstrip().expandtabs() 50 | if n in marks: 51 | c = red(c) 52 | if n in annotations: 53 | a = yellow('# ' + annotations[n]) 54 | else: 55 | a = '' 56 | print ' %4i %s %-80s %s' % (n, m, c, a) 57 | lastprinted = n 58 | elif lastprinted == n - 1: 59 | print bold(black(' %4s' % ('.' * len(str(n))))) 60 | else: 61 | pass 62 | -------------------------------------------------------------------------------- /idk/dwexpr/LICENCE.txt: -------------------------------------------------------------------------------- 1 | Large part of the modules (pydevtools) has been developed for internal applications at CSR (http://www.csr.com/) (copyright owner). 2 | CSR allowed to release the whole project under the BSD license. -------------------------------------------------------------------------------- /idk/dwexpr/__init__.py: -------------------------------------------------------------------------------- 1 | from machine import Machine, eval_DWARF_expr 2 | from result import Result -------------------------------------------------------------------------------- /idk/include/adbicpy.h: -------------------------------------------------------------------------------- 1 | #ifndef __ADBI_ADBICPY_H__ 2 | #define __ADBI_ADBICPY_H__ 3 | 4 | #include "gcc.h" 5 | 6 | #define __adbicpy memcpy 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /idk/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H_ 2 | #define COMMON_H_ 3 | 4 | #define NAKED __attribute__ ((naked)) 5 | #define ALWAYS_INLINE static inline __attribute__((always_inline)) 6 | 7 | #define NULL (0) 8 | 9 | typedef unsigned long size_t; 10 | typedef signed long ssize_t; 11 | 12 | #define ADBI_HANDLER_ATTR __attribute__((used)) 13 | 14 | int adbi_dummy() __attribute__((used, weak)); 15 | int adbi_dummy() { return 0; } 16 | 17 | #endif /* COMMON_H_ */ 18 | -------------------------------------------------------------------------------- /idk/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef ERRNO_H_ 2 | #define ERRNO_H_ 3 | 4 | #define EPERM 1 5 | #define ENOENT 2 6 | #define ESRCH 3 7 | #define EINTR 4 8 | #define EIO 5 9 | #define ENXIO 6 10 | #define E2BIG 7 11 | #define ENOEXEC 8 12 | #define EBADF 9 13 | #define ECHILD 10 14 | #define EAGAIN 11 15 | #define ENOMEM 12 16 | #define EACCES 13 17 | #define EFAULT 14 18 | #define ENOTBLK 15 19 | #define EBUSY 16 20 | #define EEXIST 17 21 | #define EXDEV 18 22 | #define ENODEV 19 23 | #define ENOTDIR 20 24 | #define EISDIR 21 25 | #define EINVAL 22 26 | #define ENFILE 23 27 | #define EMFILE 24 28 | #define ENOTTY 25 29 | #define ETXTBSY 26 30 | #define EFBIG 27 31 | #define ENOSPC 28 32 | #define ESPIPE 29 33 | #define EROFS 30 34 | #define EMLINK 31 35 | #define EPIPE 32 36 | #define EDOM 33 37 | #define ERANGE 34 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /idk/include/futex.h: -------------------------------------------------------------------------------- 1 | #ifndef FUTEX_H_ 2 | #define FUTEX_H_ 3 | 4 | #include "common.h" 5 | 6 | #include "syscall_template.h" 7 | 8 | #include "time.h" 9 | 10 | #define FUTEX_PRIVATE_FLAG 128 11 | #define FUTEX_WAIT 0 12 | #define FUTEX_WAKE 1 13 | 14 | #define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) 15 | #define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) 16 | 17 | #ifdef __aarch64__ 18 | 19 | SYSCALL_6_ARGS(get_nr(__NR_futex), 20 | int, futex, int * uaddr, int op, int val, const struct timespec * timeout, int * uaddr2, int val3); 21 | 22 | #else 23 | 24 | SYSCALL_6_ARGS(get_nr(240), 25 | int, futex, int * uaddr, int op, int val, const struct timespec * timeout, int * uaddr2, int val3); 26 | 27 | #endif 28 | 29 | #endif /* FUTEX_H_ */ 30 | -------------------------------------------------------------------------------- /idk/include/gcc.h: -------------------------------------------------------------------------------- 1 | #ifndef GCC_H_ 2 | #define GCC_H_ 3 | 4 | #include "common.h" 5 | 6 | int memcmp(const void * s1, const void * s2, size_t n) __attribute__((weak, alias("__adbi_memcmp"))); 7 | void * memset(void * dst, int c, size_t n) __attribute__((weak, alias("__adbi_memset"))); 8 | void * memcpy(void * dst, const void * src, size_t count) __attribute__((weak, alias("__adbi_memcpy"))); 9 | void * memmove(void * dst, const void * src, size_t count) __attribute__((weak, alias("__adbi_memmove"))); 10 | 11 | int __adbi_memcmp(const void * s1, const void * s2, size_t n) 12 | { 13 | const unsigned char * p1 = s1; 14 | const unsigned char * end1 = p1 + n; 15 | const unsigned char * p2 = s2; 16 | int d = 0; 17 | 18 | for(;;) { 19 | if (d || p1 >= end1) 20 | break; 21 | d = (int)*p1++ - (int)*p2++; 22 | } 23 | 24 | return d; 25 | } 26 | 27 | void * __adbi_memset(void * dst, int c, size_t n) 28 | { 29 | char * q = dst; 30 | char * end = q + n; 31 | 32 | for (;;) { 33 | if (q >= end) 34 | break; 35 | *q++ = (char) c; 36 | } 37 | 38 | return dst; 39 | } 40 | 41 | void * __adbi_memcpy(void * dst, const void * src, size_t count) { 42 | char * dstc = dst; 43 | char * srcc = src; 44 | while (count--) { 45 | *dstc = *srcc; 46 | ++dstc; 47 | ++srcc; 48 | } 49 | 50 | return dst; 51 | } 52 | 53 | void * __adbi_memmove(void * dst, const void * src, size_t count) { 54 | if (src == dst) 55 | return dst; 56 | else if ((dst < src) || ((src + count) < dst)) 57 | return memcpy(dst, src, count); 58 | 59 | char * dstc = dst + count; 60 | char * srcc = src + count; 61 | while (count--) { 62 | *dstc = *srcc; 63 | --dstc; 64 | --srcc; 65 | } 66 | 67 | return dst; 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /idk/include/personality.h: -------------------------------------------------------------------------------- 1 | #ifndef PERSONALITY_H_ 2 | #define PERSONALITY_H_ 3 | 4 | #include "syscall_template.h" 5 | 6 | /* 7 | * Flags for bug emulation. 8 | * 9 | * These occupy the top three bytes. 10 | */ 11 | enum { 12 | UNAME26 = 0x0020000, 13 | ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ 14 | FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors 15 | * (signal handling) 16 | */ 17 | MMAP_PAGE_ZERO = 0x0100000, 18 | ADDR_COMPAT_LAYOUT = 0x0200000, 19 | READ_IMPLIES_EXEC = 0x0400000, 20 | ADDR_LIMIT_32BIT = 0x0800000, 21 | SHORT_INODE = 0x1000000, 22 | WHOLE_SECONDS = 0x2000000, 23 | STICKY_TIMEOUTS = 0x4000000, 24 | ADDR_LIMIT_3GB = 0x8000000, 25 | }; 26 | 27 | #ifdef __aarch54__ 28 | 29 | SYSCALL_1_ARGS(get_nr(__NR_personality), 30 | int, personality, unsigned long persona); 31 | 32 | #else 33 | 34 | SYSCALL_1_ARGS(get_nr(136), 35 | int, personality, unsigned long persona); 36 | 37 | #endif 38 | 39 | #endif /* PERSONALITY_H_ */ 40 | -------------------------------------------------------------------------------- /idk/include/syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCALLS_H_ 2 | #define SYSCALLS_H_ 3 | 4 | #include "mmap.h" 5 | #include "time.h" 6 | #include "futex.h" 7 | #include "io.h" 8 | #include "net.h" 9 | #include "personality.h" 10 | 11 | #endif /* SYSCALLS_H_ */ 12 | -------------------------------------------------------------------------------- /idk/include/time.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_H_ 2 | #define TIME_H_ 3 | 4 | typedef long time_t; 5 | typedef long suseconds_t; 6 | 7 | struct timespec { 8 | time_t tv_sec; /* seconds */ 9 | long tv_nsec; /* nanoseconds */ 10 | }; 11 | 12 | struct timeval { 13 | time_t tv_sec; /* seconds */ 14 | suseconds_t tv_usec; /* microseconds */ 15 | }; 16 | 17 | struct timezone { 18 | int tz_minuteswest; 19 | int tz_dsttime; 20 | }; 21 | 22 | #ifdef __aarch64__ 23 | 24 | SYSCALL_2_ARGS(get_nr(__NR_gettimeofday), 25 | int, gettimeofday, struct timeval * tv, struct timezone * tz); 26 | 27 | SYSCALL_2_ARGS(get_nr(__NR_nanosleep), 28 | int, nanosleep, const struct timespec * req, struct timespec * rem); 29 | 30 | #else 31 | 32 | SYSCALL_2_ARGS(get_nr(78), int, gettimeofday, struct timeval * tv, struct timezone * tz); 33 | 34 | SYSCALL_2_ARGS(get_nr(162), int, nanosleep, const struct timespec * req, struct timespec * rem); 35 | 36 | #endif 37 | 38 | /* Simplified variant of the sleep function. */ 39 | static void sleep(unsigned int seconds) { 40 | struct timespec t; 41 | t.tv_sec = seconds; 42 | t.tv_nsec = 0; 43 | nanosleep(&t, NULL); 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /idk/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __ADBI_TYPES_H__ 2 | #define __ADBI_TYPES_H__ 3 | 4 | /* Further declarations heavily depend on features available only in GCC. */ 5 | #ifndef __GNUC__ 6 | #error "Incompatible compiler." 7 | #endif 8 | 9 | 10 | /* Make sure the sizes of integer types match the values defined by the GNU C standard. */ 11 | #if __SIZEOF_SHORT__ != 2 12 | #error "sizeof(short) != 2" 13 | #endif 14 | 15 | #if __SIZEOF_INT__ != 4 16 | #error "sizeof(int) != 4" 17 | #endif 18 | 19 | #if __SIZEOF_LONG_LONG__ != 8 20 | #error "sizeof(long long) != 8" 21 | #endif 22 | 23 | 24 | /* Define the floating point type macros. */ 25 | #undef __adbi_fp32_t 26 | #undef __adbi_fp64_t 27 | #undef __adbi_fp128_t 28 | 29 | #if __SIZEOF_FLOAT__ == 4 30 | #undef __adbi_fp32_t 31 | #define __adbi_fp32_t float 32 | #elif __SIZEOF_FLOAT__ == 8 33 | #undef __adbi_fp64_t 34 | #define __adbi_fp64_t float 35 | #elif __SIZEOF_FLOAT__ == 16 36 | #undef __adbi_fp128_t 37 | #define __adbi_fp128_t float 38 | #endif 39 | 40 | #if __SIZEOF_DOUBLE__ == 4 41 | #undef __adbi_fp32_t 42 | #define __adbi_fp32_t double 43 | #elif __SIZEOF_DOUBLE__ == 8 44 | #undef __adbi_fp64_t 45 | #define __adbi_fp64_t double 46 | #elif __SIZEOF_DOUBLE__ == 16 47 | #undef __adbi_fp128_t 48 | #define __adbi_fp128_t double 49 | #endif 50 | 51 | #if __SIZEOF_LONG_DOUBLE__ == 4 52 | #undef __adbi_fp32_t 53 | #define __adbi_fp32_t long double 54 | #elif __SIZEOF_LONG_DOUBLE__ == 8 55 | #undef __adbi_fp64_t 56 | #define __adbi_fp64_t long double 57 | #elif __SIZEOF_LONG_DOUBLE__ == 16 58 | #undef __adbi_fp128_t 59 | #define __adbi_fp128_t long double 60 | #endif 61 | 62 | 63 | /* Warn about missing types. */ 64 | #ifndef __adbi_fp32_t 65 | #warning "Architecture does not support 32 bit floating point values." 66 | #endif 67 | 68 | #ifndef __adbi_fp64_t 69 | #warning "Architecture does not support 64 bit floating point values." 70 | #endif 71 | 72 | #ifndef __adbi_fp128_t 73 | /* 128-bit floats are unusual. Don't complain if they are missing. */ 74 | // #warning Architecture does not support 128 bit floating point values. 75 | #endif 76 | 77 | #endif -------------------------------------------------------------------------------- /idk/include/unix.h: -------------------------------------------------------------------------------- 1 | #ifndef UNIX_H_ 2 | #define UNIX_H_ 3 | 4 | #include "common.h" 5 | #include "syscall_template.h" 6 | 7 | typedef int pid_t; 8 | 9 | typedef unsigned int uid_t; 10 | typedef unsigned int gid_t; 11 | 12 | SYSCALL_0_ARGS(get_nr(__NR_getpid), pid_t, getpid, void); 13 | SYSCALL_0_ARGS(get_nr(__NR_getuid), pid_t, getuid, void); 14 | SYSCALL_0_ARGS(get_nr(__NR_getgid), pid_t, getgid, void); 15 | SYSCALL_0_ARGS(get_nr(__NR_geteuid), pid_t, geteuid, void); 16 | SYSCALL_0_ARGS(get_nr(__NR_getegid), pid_t, getegid, void); 17 | SYSCALL_0_ARGS(get_nr(__NR_gettid), pid_t, gettid, void); 18 | 19 | #endif /* UNIX_H_ */ 20 | -------------------------------------------------------------------------------- /idk/include/varargs.h: -------------------------------------------------------------------------------- 1 | /* Variable argument list support */ 2 | #ifndef VARARGS_H_ 3 | #define VARARGS_H_ 4 | 5 | #ifndef _VA_LIST 6 | typedef __builtin_va_list va_list; 7 | #define _VA_LIST 8 | #endif 9 | 10 | #define va_start(ap, param) __builtin_va_start(ap, param) 11 | #define va_end(ap) __builtin_va_end(ap) 12 | #define va_arg(ap, type) __builtin_va_arg(ap, type) 13 | 14 | #define __va_copy(dst, src) __builtin_va_copy(dst, src) 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /idk/inject.x: -------------------------------------------------------------------------------- 1 | /* OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") */ 2 | /* OUTPUT_ARCH(arm) */ 3 | ENTRY(__adbi$entry) 4 | SECTIONS 5 | { 6 | . = 0x00000000 + SIZEOF_HEADERS; 7 | 8 | .adbi : { 9 | *(.rodata) 10 | *(.rodata.*) 11 | *(.data) *(.data.*) 12 | *(.bss) *(.bss.*) 13 | *(.text) 14 | *(.text.*) 15 | *(.adbi) 16 | *(.adbi.*) 17 | } = 0 18 | 19 | } 20 | -------------------------------------------------------------------------------- /idk/libasdd/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.1' -------------------------------------------------------------------------------- /idk/libasdd/disarm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from ctypes import CDLL 3 | from ctypes import c_char_p, c_uint16, c_uint32 4 | import copy 5 | import os 6 | 7 | __libasdd_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'libasdd.so') 8 | __libasdd = CDLL(__libasdd_path) 9 | 10 | def __init_fn(name, res, args): 11 | getattr(__libasdd, name).restype = res 12 | getattr(__libasdd, name).argtypes = args 13 | 14 | __init_fn('disarm', c_char_p, [c_uint32]) 15 | __init_fn('disthumb', c_char_p, [c_uint16]) 16 | __init_fn('disthumb2', c_char_p, [c_uint32]) 17 | 18 | __init_fn('disarma', c_char_p, [c_uint32, c_uint32]) 19 | __init_fn('disthumba', c_char_p, [c_uint16, c_uint32]) 20 | __init_fn('disthumb2a', c_char_p, [c_uint32, c_uint32]) 21 | 22 | def disarm(u32): 23 | return copy.deepcopy(__libasdd.disarm(u32)) 24 | 25 | def disthumb(u16): 26 | return copy.deepcopy(__libasdd.disthumb(u16)) 27 | 28 | def disthumb2(u32): 29 | return copy.deepcopy(__libasdd.disthumb2(u32)) 30 | 31 | def disarma(u32, pc): 32 | return copy.deepcopy(__libasdd.disarma(u32, pc)) 33 | 34 | def disathumba(u16, pc): 35 | return copy.deepcopy(__libasdd.disthumba(u16, pc)) 36 | 37 | def disthumb2a(u32, pc): 38 | return copy.deepcopy(__libasdd.disthumb2a(u32, pc)) 39 | 40 | def is_thumb2(insn): 41 | if insn > 0xffff: 42 | raise TypeError("is_thumb2 tests 16-bit long halfwords") 43 | 44 | return insn >= 0xe800 45 | 46 | def thumbcat(first, second): 47 | return (first << 16) + second 48 | 49 | def intify(string): 50 | res = 0 51 | for idx, byte in enumerate(string): 52 | res += ord(byte) << (8 * idx) 53 | return res 54 | 55 | if __name__ == '__main__': 56 | pass -------------------------------------------------------------------------------- /idk/libasdd/libasdd.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samsung/ADBI/3e424c45386b0a36c57211da819021cb1929775a/idk/libasdd/libasdd.so -------------------------------------------------------------------------------- /idk/tests/Makefile: -------------------------------------------------------------------------------- 1 | CC = agcc 2 | CFLAGS = -ggdb3 3 | 4 | SRC = $(wildcard *.c) 5 | ASM = $(wildcard *.S) 6 | OUT = $(SRC:.c=) 7 | ASMOUT = $(ASM:.S=) 8 | 9 | all: $(OUT) $(ASMOUT) 10 | 11 | $(OUT): % : %.c 12 | echo ' [CC] $@' 13 | $(CC) $(CFLAGS) $^ -o $@ 14 | 15 | $(ASMOUT): % : %.S 16 | echo ' [CC] $@' 17 | $(CC) $(CFLAGS) $^ -o $@ 18 | 19 | clean: 20 | echo 'Cleaning up...' 21 | $(RM) $(OUT) $(ASMOUT) 22 | 23 | .SILENT: 24 | -------------------------------------------------------------------------------- /idk/tests/args.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int __attribute__((naked)) sub(int a, int b) { 6 | __asm__("sub r0, r0, r1 \n" 7 | "bx lr \n"); 8 | } 9 | 10 | int add(int a, int b) { return a + b; } 11 | 12 | int sum(int count, ...) { 13 | int ret = 0; 14 | 15 | va_list args; 16 | va_start(args, count); 17 | 18 | while (count--) { 19 | int e = va_arg(args, int); 20 | ret = add(ret, e); 21 | } 22 | 23 | va_end(args); 24 | 25 | return ret; 26 | } 27 | 28 | int main(int argc, char * argv[]) { 29 | 30 | printf("%d\n", sum(5, 1, 2, 3, 4, 5)); 31 | 32 | } -------------------------------------------------------------------------------- /idk/tests/assembly.S: -------------------------------------------------------------------------------- 1 | 2 | fibo: 3 | .global fibo; 4 | .type fibo, %function; 5 | 6 | // n <= 1 7 | cmp r0, #1 8 | bxle lr 9 | 10 | // n > 1 11 | push {r4, lr} 12 | 13 | // r4 = n - 2 14 | sub r4, r0, #2 15 | 16 | // r0 = n - 1 17 | sub r0, r0, #1 18 | 19 | // r0 = fibo(r0) = fibo(n - 1) 20 | bl fibo 21 | 22 | // r0, r4 = n - 2, fibo(n - 1) 23 | eor r0, r0, r4 24 | eor r4, r0, r4 25 | eor r0, r0, r4 26 | 27 | // r0 = fibo(r0) == fibo(n - 2) 28 | bl fibo 29 | 30 | // r0 = fibo(n - 2) + fibo(n - 1) 31 | add r0, r0, r4 32 | 33 | // return 34 | pop {r4, pc} 35 | 36 | 37 | main: 38 | .global main; 39 | .type main, %function; 40 | 41 | cmp r0, #2 42 | movne r0, #-1 43 | bxne lr 44 | 45 | push { lr } 46 | 47 | ldr r0, [r1, #4] 48 | bl atoi 49 | 50 | bl fibo 51 | 52 | pop { pc } -------------------------------------------------------------------------------- /idk/tests/fibo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int fibo(unsigned int n) { 4 | if (n <= 1) 5 | return n; 6 | else 7 | return fibo(n - 1) + fibo(n - 2); 8 | } 9 | 10 | int main(int argc, char * argv[]) { 11 | if (argc != 2) { 12 | printf("Usage: %s N\n", argv[0]); 13 | } else { 14 | unsigned int n = (unsigned int) atoi(argv[1]); 15 | printf("fibo(%u) = %u\n", n, fibo(n)); 16 | } 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /idk/tests/functions.c: -------------------------------------------------------------------------------- 1 | 2 | int fun1(int a, int b) { 3 | return a * a + 2 * a * b + b * b; 4 | } 5 | 6 | __attribute__((naked)) int fun2(int a, int b) { 7 | __asm__(" cmp r0, r1 \n" 8 | " movle r0, r1 \n" 9 | " bx lr \n"); 10 | } 11 | 12 | int fun3(int a, int b) { 13 | int c = fun2(a, b); 14 | return fun1(a, b); 15 | } 16 | 17 | int main() { 18 | return 0; 19 | } -------------------------------------------------------------------------------- /idk/tests/tls.c: -------------------------------------------------------------------------------- 1 | 2 | __thread int a = 12; 3 | 4 | int main() { 5 | ++a; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /idk/tests/vars.c: -------------------------------------------------------------------------------- 1 | int global_foo = 12; 2 | 3 | void * ptr = 0x8000; 4 | 5 | static int unused(int x, int y) { 6 | return (x + y) / 2; 7 | } 8 | 9 | static int add(int a, int b) { 10 | int local_foo = a + b + global_foo; 11 | { 12 | int local_foo_nested = a * a - b; 13 | local_foo -= local_foo_nested; 14 | } 15 | return local_foo; 16 | } 17 | 18 | int main(int argc, const char * argv[]) { 19 | return add(12, 13); 20 | } -------------------------------------------------------------------------------- /idk/toarray: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | __author__ = 'Michał Leśniewski' 5 | __contact__ = 'm.lesniewski@samsung.com' 6 | __version__ = '0.1a' 7 | 8 | import argparse 9 | import os 10 | 11 | def main(): 12 | try: 13 | parser = argparse.ArgumentParser(description='Create or analyze ADBI injectacle files.') 14 | parser.add_argument('-V', '--version', action='version', 15 | version="%(prog)s (ADBI 3.0 project) " + __version__) 16 | 17 | parser.add_argument('input', type=str, help='input file name') 18 | parser.add_argument('name', type=str, help='symbol file name') 19 | 20 | args = parser.parse_args(); 21 | 22 | output = args.input + '.c' 23 | name = args.name.strip() 24 | 25 | with open(output, 'w') as outfile: 26 | 27 | length = 0 28 | 29 | outfile.write('/* WARNING: This file was generated automatically. */\n\n') 30 | outfile.write('#include "injectable/injectable.h"\n\n') 31 | outfile.write('static char %s_data [] = {\n' % name) 32 | 33 | with open(args.input, 'rb') as infile: 34 | data = infile.read() 35 | 36 | ascii = '' 37 | line = '' 38 | 39 | for n, c in enumerate(data): 40 | if n % 16 == 0: 41 | if line: 42 | outfile.write(' /* %6x */ %-96s // | %s | \n' % (n - 16, line, ascii)) 43 | ascii = '' 44 | line = '' 45 | line += '0x%02x, ' % ord(c) 46 | ascii += c if 32 <= ord(c) < 127 else '.' 47 | outfile.write(' /* %6x */ %-96s // | %s |' % (n - 16, line, ascii)) 48 | outfile.write('\n};\n\n') 49 | outfile.write('injectable_t * %s_get(void) {\n' % name) 50 | outfile.write(' static injectable_t * inj = NULL;\n') 51 | outfile.write(' if (!inj)\n') 52 | outfile.write(' inj = injectable_init_builtin((void *) %s_data, %i);\n' % (name, len(data))) 53 | outfile.write(' return inj;\n') 54 | outfile.write('}\n\n') 55 | 56 | except KeyboardInterrupt: 57 | print 'Aborted.' 58 | 59 | except IOError, e: 60 | print e 61 | raise SystemExit(1) 62 | 63 | main() 64 | -------------------------------------------------------------------------------- /inj/adbi/Makefile: -------------------------------------------------------------------------------- 1 | DIR := $(dir $(lastword $(MAKEFILE_LIST)))$(SELF_DIR) 2 | IDK := $(DIR)/../../idk 3 | MKINJ := $(IDK)/mkinj 4 | TOARRAY := $(IDK)/toarray 5 | 6 | NAME := adbi 7 | SYM := $(NAME)_injectable 8 | SRC := $(NAME).c 9 | INJ := $(SRC:.c=.inj) 10 | INJC := $(INJ:.inj=.inj.c) 11 | 12 | $(INJC): $(INJ) 13 | @echo " [2A] $@" 14 | $(TOARRAY) $(INJ) $(SYM) 15 | 16 | $(INJ): $(SRC) 17 | @echo " [INJ] $@" 18 | $(MKINJ) --library $(NAME) --gcc $(CC) --features nofp -o $@ $(SRC) 19 | 20 | clean: 21 | $(RM) $(INJC) $(INJ) 22 | 23 | .SILENT: 24 | 25 | -------------------------------------------------------------------------------- /inj/adbi_mmap/Makefile: -------------------------------------------------------------------------------- 1 | DIR := $(dir $(lastword $(MAKEFILE_LIST)))$(SELF_DIR) 2 | IDK := $(DIR)/../../idk 3 | MKINJ := $(IDK)/mkinj 4 | TOARRAY := $(IDK)/toarray 5 | 6 | NAME := adbi_mmap 7 | SYM := $(NAME)_injectable 8 | SRC := $(NAME).c 9 | INJ := $(SRC:.c=.inj) 10 | INJC := $(INJ:.inj=.inj.c) 11 | 12 | $(INJC): $(INJ) 13 | @echo " [2A] $@" 14 | $(TOARRAY) $(INJ) $(SYM) 15 | 16 | $(INJ): $(SRC) 17 | @echo " [INJ] $@" 18 | $(MKINJ) --library $(NAME) --gcc $(CC) --features nofp -o $@ $(SRC) 19 | 20 | clean: 21 | $(RM) $(INJC) $(INJ) 22 | 23 | .SILENT: 24 | 25 | -------------------------------------------------------------------------------- /inj/adbi_mmap/adbi_mmap.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "syscall_template.h" 3 | 4 | #ifdef __aarch64__ 5 | SYSCALL_6_ARGS(get_nr(__NR_mmap), 6 | void *, mmap, void * addr, size_t length, int prot, int flags, int fd, size_t offset); 7 | #else 8 | SYSCALL_6_ARGS(get_nr(192), 9 | void *, mmap, void * addr, size_t length, int prot, int flags, int fd, size_t offset); 10 | #endif 11 | 12 | #define PROT_READ 0x1 13 | #define PROT_WRITE 0x2 14 | #define PROT_EXEC 0x4 15 | 16 | 17 | #define MAP_PRIVATE 0x02 18 | #define MAP_ANONYMOUS 0x20 19 | 20 | GLOBAL 21 | void * adbi_mmap(unsigned int size) { 22 | return mmap(NULL, /* no address suggestion */ 23 | size, /* requested size */ 24 | PROT_READ | PROT_WRITE | PROT_EXEC, /* all permissions */ 25 | MAP_PRIVATE | MAP_ANONYMOUS, /* private mapping, no file */ 26 | -1, 0 /* fd and offset (ignored) */ 27 | ); 28 | } 29 | 30 | INIT() { 31 | return 0; 32 | } 33 | 34 | ADBI(adbi_mmap); 35 | -------------------------------------------------------------------------------- /inj/adbi_munmap/Makefile: -------------------------------------------------------------------------------- 1 | DIR := $(dir $(lastword $(MAKEFILE_LIST)))$(SELF_DIR) 2 | IDK := $(DIR)/../../idk 3 | MKINJ := $(IDK)/mkinj 4 | TOARRAY := $(IDK)/toarray 5 | 6 | NAME := adbi_munmap 7 | SYM := $(NAME)_injectable 8 | SRC := $(NAME).c 9 | INJ := $(SRC:.c=.inj) 10 | INJC := $(INJ:.inj=.inj.c) 11 | 12 | $(INJC): $(INJ) 13 | @echo " [2A] $@" 14 | $(TOARRAY) $(INJ) $(SYM) 15 | 16 | $(INJ): $(SRC) 17 | @echo " [INJ] $@" 18 | $(MKINJ) --library $(NAME) --gcc $(CC) --features nofp -o $@ $(SRC) 19 | 20 | clean: 21 | $(RM) $(INJC) $(INJ) 22 | 23 | .SILENT: 24 | 25 | -------------------------------------------------------------------------------- /inj/adbi_munmap/adbi_munmap.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "syscall_template.h" 3 | 4 | SYSCALL_2_ARGS(get_nr(__NR_munmap), int, munmap, void * address, size_t length); 5 | 6 | GLOBAL int adbi_munmap(void * address, unsigned int size) { 7 | return munmap(address, size); 8 | } 9 | 10 | INIT() { 11 | return 0; 12 | } 13 | 14 | ADBI(adbi_munmap); 15 | -------------------------------------------------------------------------------- /inj/dummy/Makefile: -------------------------------------------------------------------------------- 1 | DIR := $(dir $(lastword $(MAKEFILE_LIST)))$(SELF_DIR) 2 | IDK := $(DIR)/../../idk 3 | MKINJ := $(IDK)/mkinj 4 | 5 | NAME := dummy 6 | SYM := $(NAME)_injectable 7 | SRC := $(NAME).c 8 | INJ := $(SRC:.c=.inj) 9 | INJC := $(INJ:.inj=.inj.c) 10 | 11 | $(INJ): $(SRC) 12 | @echo " [INJ] $@" 13 | $(MKINJ) --gcc $(CC) --library $(SRC) $(NAME) 14 | 15 | clean: 16 | $(RM) $(INJC) $(INJ) 17 | 18 | .SILENT: 19 | 20 | -------------------------------------------------------------------------------- /inj/dummy/dummy.c: -------------------------------------------------------------------------------- 1 | 2 | INIT { 3 | 4 | } 5 | 6 | GLOBAL void dummy(void) { 7 | 8 | } 9 | 10 | EXPORT(dummy); 11 | ADBI(dummy); -------------------------------------------------------------------------------- /injectable/injectable.h: -------------------------------------------------------------------------------- 1 | #ifndef _INJECTABLE_H_ 2 | #define _INJECTABLE_H_ 3 | 4 | #include "process/process.h" 5 | #include "process/segment.h" 6 | #include "injfile.h" 7 | 8 | struct injectable_t { 9 | /* unique id */ 10 | unsigned int id; 11 | 12 | /* inj file name */ 13 | const char * filename; 14 | 15 | /* injectable file */ 16 | injfile_t * injfile; 17 | 18 | /* reference count */ 19 | refcnt_t references; 20 | 21 | /* is the injectable built-in? */ 22 | bool builtin; 23 | }; 24 | 25 | typedef struct injectable_t injectable_t; 26 | 27 | injectable_t * injectable_init_builtin(void * buffer, size_t size); 28 | const injectable_t * injectable_load(const char * filename, const char ** msg); 29 | 30 | bool injectable_unload(unsigned int iid, const char ** msg); 31 | 32 | bool injectable_is_library(const injectable_t * injectable); 33 | 34 | const injectable_t * injectable_get(unsigned int iid); 35 | const injectable_t * injectable_get_library(const char * name); 36 | const injectable_t * injectable_get_binding(const char * path); 37 | 38 | offset_t injectable_get_symbol(const injectable_t * injectable, const char * name); 39 | offset_t injectable_get_exported_symbol(const injectable_t * injectable, const char * name); 40 | 41 | void injections_init(thread_t * thread, segment_t * segment); 42 | void injections_gone(thread_t * thread, segment_t * segment); 43 | 44 | extern injectable_t * adbi_injectable; 45 | extern injectable_t * adbi_mmap_injectable; 46 | extern injectable_t * adbi_munmap_injectable; 47 | 48 | bool injectable_init(); 49 | void injectable_cleanup(); 50 | 51 | typedef void (injectable_callback_t)(const injectable_t * injectable); 52 | void injectable_iter(injectable_callback_t callback); 53 | 54 | typedef void (injectable_symbol_callback_t)(const injectable_t * injectable, const injfile_symbol_t * symbol); 55 | void injectable_iter_dependencies(const injectable_t * injectable, injectable_callback_t callback, 56 | injectable_symbol_callback_t unresolved_import_callback); 57 | 58 | typedef void (injectable_iter_fn_t)(const injectable_t * injectable, injfile_symbol_callback_t callback); 59 | 60 | injectable_iter_fn_t injectable_iter_exports; 61 | injectable_iter_fn_t injectable_iter_imports; 62 | injectable_iter_fn_t injectable_iter_adbi; 63 | 64 | void injectable_iter_tracepoints(const injectable_t * injectable, injfile_tpoint_callback_t callback); 65 | 66 | #define INJECTABLE_ITER_IMPORTS(injectable, symbol) INJFILE_ITER_IMPORTS(injectable->injfile, symbol) 67 | #define INJECTABLE_ITER_EXPORTS(injectable, symbol) INJFILE_ITER_EXPORTS(injectable->injfile, symbol) 68 | #define INJECTABLE_ITER_ADBI(injectable, symbol) INJFILE_ITER_ADBI(injectable->injfile, symbol) 69 | #define INJECTABLE_ITER_TPOINTS(injectable, tpoint) INJFILE_ITER_TPOINTS(injectable->injfile, tpoint) 70 | 71 | const char * str_injectable(const injectable_t * injectable); 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /injection/fncall.h: -------------------------------------------------------------------------------- 1 | #ifndef FNCALL_H 2 | #define FNCALL_H 3 | 4 | #include "arch.h" 5 | #include "process/process.h" 6 | #include "process/thread.h" 7 | #include "process/segment.h" 8 | 9 | typedef struct call_context_t call_context_t; 10 | 11 | bool fncall_allocate(thread_t * thread, size_t size, address_t * address); 12 | bool fncall_mmap(thread_t * thread, address_t * res, address_t addr, size_t size, int prot, int flags, int fd, long offset); 13 | bool fncall_realloc(thread_t * thread, address_t * address, size_t old_size, size_t new_size); 14 | bool fncall_free(thread_t * thread, address_t address, size_t size); 15 | 16 | int fncall_get_errno(regval_t r0_val); 17 | bool fncall_alloc_load_call(thread_t * thread, unsigned char * function_text, 18 | size_t size, address_t entry, call_context_t * context); 19 | size_t fncall_align_to_page(size_t size); 20 | 21 | bool fncall_call_adbi(thread_t * thread, address_t address, int arg1, int arg2, int arg3, int arg4, 22 | int * ret); 23 | bool fncall_call_mprotect(thread_t * thread, address_t address, size_t size, int prot); 24 | 25 | bool fncall_runtil(thread_t * thread, address_t stopat); 26 | bool fncall_runtil_seg(thread_t * thread, segment_t * segment); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /injection/inject.h: -------------------------------------------------------------------------------- 1 | #ifndef INJECT_H 2 | #define INJECT_H 3 | 4 | #include "injection.h" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /injection/injection.h: -------------------------------------------------------------------------------- 1 | #ifndef INJECTION_H_ 2 | #define INJECTION_H_ 3 | 4 | #include "tree.h" 5 | #include "fncall.h" 6 | #include "injectable/injectable.h" 7 | 8 | typedef struct process_t process_t; 9 | typedef struct thread_t thread_t; 10 | typedef struct binary_t binary_t; 11 | 12 | /* Injectable, which is currently loaded into the memory of a process. */ 13 | typedef struct injection_t { 14 | 15 | /* Process where the code is injected. */ 16 | process_t * process; 17 | 18 | /* Address in inferior process, where the injectable is loaded */ 19 | address_t address; 20 | 21 | /* Injectable loaded into memory */ 22 | const injectable_t * injectable; 23 | 24 | /* Reference count to this injectable */ 25 | unsigned int references; 26 | 27 | } injection_t; 28 | 29 | injection_t * injection_get(const process_t * process, const injectable_t * injectable); 30 | const injection_t * injection_get_by_address(const process_t * process, address_t address); 31 | 32 | void injection_fork(process_t * child, process_t * parent); 33 | void injection_reset(process_t * process); 34 | 35 | void injection_notify_new_thread(thread_t * thread); 36 | 37 | injection_t * inject_adbi(thread_t * thread); 38 | bool uninject_adbi(thread_t * thread); 39 | 40 | /* Check if the given injection is the ADBI base injection. */ 41 | inline static bool injection_is_adbi(injection_t * injection) { 42 | return injection->injectable == adbi_injectable; 43 | } 44 | 45 | /* Get the ADBI base injection for the given process. */ 46 | inline static injection_t * injection_get_adbi(const process_t * process) { 47 | return injection_get(process, adbi_injectable); 48 | } 49 | 50 | address_t injection_get_adbi_function_address(const process_t * process, const char * symbol); 51 | 52 | void injection_iter(process_t * process, void callback(injection_t *)); 53 | void injection_detach(thread_t * thread); 54 | 55 | void injection_detach_single(thread_t * thread, injection_t * injection); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /lib/asdd/include/disarm.h: -------------------------------------------------------------------------------- 1 | #ifndef _DISARM_H 2 | #define _DISARM_H 3 | 4 | #include 5 | #include 6 | 7 | /* The following functions disassemble a single instruction and return a string containing a human readable string. 8 | * The returned pointer points to an internal thread local buffer, which does not need to be freed. Note that the 9 | * functions always return a pointer to the same buffer, only the contents of the buffer change. */ 10 | const char * disarm(uint32_t insn); 11 | const char * disthumb(uint16_t insn); 12 | const char * disthumb2(uint32_t insn); 13 | 14 | /* The following functions are extended forms of the disassembling functions above. They accept an additional pc 15 | * parameter, which specifies the address of the given instruction. This value is used when evaluating branch 16 | * destinations and addresses. */ 17 | const char * disarma(uint32_t insn, uint32_t pc); 18 | const char * disthumba(uint16_t insn, uint32_t pc); 19 | const char * disthumb2a(uint32_t insn, uint32_t pc); 20 | 21 | /* Return true if the given thumb opcode represents the first half of a 32-bit instruction (and should be disassembled) 22 | * using disthumb2 instead of disthumb. */ 23 | static inline bool is_thumb2(uint16_t insn) { return insn >= 0xe800; } 24 | 25 | /* Merge two 16-bit thumb instructions to form a 32-bit thumb instruction. */ 26 | static inline uint32_t thumbcat(uint16_t first, uint16_t second) { 27 | return (((uint32_t) first) << 16) | ((uint32_t) second); 28 | } 29 | 30 | #endif /* _DISARM_H */ -------------------------------------------------------------------------------- /lib/asdd/include/likely.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIKELY_H 2 | #define _LIKELY_H 3 | 4 | #ifndef __GNUC__ 5 | #define __builtin_expect(a, b) (a) 6 | #endif 7 | 8 | #define likely(x) __builtin_expect(!!(x), 1) 9 | #define unlikely(x) __builtin_expect(!!(x), 0) 10 | 11 | #endif -------------------------------------------------------------------------------- /lib/asdd/include/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOGGER_H 2 | #define _LOGGER_H 3 | 4 | #ifndef __GNUC__ 5 | #define __builtin_expect(a, b) (a) 6 | #endif 7 | 8 | #ifndef LOGGER_WIDTH 9 | #define LOGGER_WIDTH 80 10 | #endif 11 | 12 | #ifndef LOGGER_INDENT 13 | #define LOGGER_INDENT 4 14 | #endif 15 | 16 | #define LOGGER_SILENT 0 17 | #define LOGGER_FATAL 1 18 | #define LOGGER_ERROR 2 19 | #define LOGGER_WARNING 3 20 | #define LOGGER_INFO 4 21 | #define LOGGER_VERBOSE 5 22 | #define LOGGER_DEBUG 6 23 | 24 | extern unsigned int logger_level; 25 | 26 | void logger_printf(char * fmt, ...) __attribute__((format(printf, 1, 2))); 27 | 28 | #define logger_printf_magic(level, ...) \ 29 | do { \ 30 | if (__builtin_expect(!!(level <= logger_level), 0)) { \ 31 | logger_printf(__VA_ARGS__); \ 32 | } \ 33 | } while (0) 34 | 35 | #define critical(...) do { logger_printf(__VA_ARGS__); } while (0) 36 | #define fatal(...) logger_printf_magic(LOGGER_FATAL, __VA_ARGS__) 37 | #define error(...) logger_printf_magic(LOGGER_ERROR, __VA_ARGS__) 38 | #define warning(...) logger_printf_magic(LOGGER_WARNING, __VA_ARGS__) 39 | #define info(...) logger_printf_magic(LOGGER_INFO, __VA_ARGS__) 40 | #define verbose(...) logger_printf_magic(LOGGER_VERBOSE, __VA_ARGS__) 41 | 42 | #ifdef NDEBUG 43 | #define debug(...) do { /* nop */ } while (0) 44 | #else 45 | #define debug(...) logger_printf_magic(LOGGER_DEBUG, __VA_ARGS__) 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /lib/asdd/include/stringbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRINGBUF_H 2 | #define _STRINGBUF_H 3 | 4 | #define STRINGBUF_SIZE 0x1000 5 | 6 | /* Write formatted text into a temporary string buffer. The returned buffer must not be freed -- it is a thread local 7 | * variable. The maximum length of a single output string is STRINGBUF_SIZE. If a string does not fit, it is trimmed 8 | * and its last 3 chars are dots ("..."). 9 | * 10 | * This function is meant to be used for creation of short strings for temporary use. The strings do not need to be 11 | * freed, so it can be used to achieve clean code (in comparison to the usual sequence), i.e.: 12 | * 13 | * the usual approach: 14 | * char * tmp[20]; 15 | * sprintf(tmp, "foo = %i", foo); 16 | * ...use tmp... 17 | * 18 | * can be replaced by: 19 | * char * tmp = stringbuf_printf("foo = %i", foo); 20 | * ...use tmp... 21 | * 22 | * Pointers returned by this function point into an internal buffer. Each call to stringbuf_printf allocates some space 23 | * in the buffer, writes the output text there and returns the pointer to the beginning of the text. Allocation is 24 | * trivial -- the function remembers where the last returned string ended and starts writing the next one just after 25 | * that location. If there is not enough space remaining in the buffer, it starts writing at the beginning of the 26 | * buffer (so in fact this is a special case of a circular buffer). This means that every string returned by this 27 | * function will eventually be overwritten. However, it is possible to generate many short strings and use them 28 | * simultaneously (as long as their total length is less than STRINGBUF_SIZE). 29 | */ 30 | __attribute__((format(printf, 1, 2))) 31 | const char * stringbuf_printf(char * fmt, ...); 32 | 33 | #endif -------------------------------------------------------------------------------- /lib/asdd/libasdd.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samsung/ADBI/3e424c45386b0a36c57211da819021cb1929775a/lib/asdd/libasdd.a -------------------------------------------------------------------------------- /lib/asdd/libasdd64.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samsung/ADBI/3e424c45386b0a36c57211da819021cb1929775a/lib/asdd/libasdd64.a -------------------------------------------------------------------------------- /lib/capstone/LICENSE.TXT: -------------------------------------------------------------------------------- 1 | This is the software license for Capstone disassembly framework. 2 | Capstone has been designed & implemented by Nguyen Anh Quynh 3 | 4 | See http://www.capstone-engine.org for further information. 5 | 6 | Copyright (c) 2013, COSEINC. 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | * Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | * Neither the name of the developer(s) nor the names of its 18 | contributors may be used to endorse or promote products derived from this 19 | software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /lib/capstone/include/platform.h: -------------------------------------------------------------------------------- 1 | /* Capstone Disassembly Engine */ 2 | /* By Axel Souchet & Nguyen Anh Quynh, 2014 */ 3 | 4 | // handle C99 issue (for pre-2013 VisualStudio) 5 | #ifndef CAPSTONE_PLATFORM_H 6 | #define CAPSTONE_PLATFORM_H 7 | 8 | #if !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) 9 | // MSVC 10 | 11 | // stdbool.h 12 | #if (_MSC_VER < 1800) 13 | #ifndef __cplusplus 14 | typedef unsigned char bool; 15 | #define false 0 16 | #define true 1 17 | #endif 18 | 19 | #else 20 | // VisualStudio 2013+ -> C99 is supported 21 | #include 22 | #endif 23 | 24 | #else // not MSVC -> C99 is supported 25 | #include 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /lib/capstone/libcapstone.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Samsung/ADBI/3e424c45386b0a36c57211da819021cb1929775a/lib/capstone/libcapstone.a -------------------------------------------------------------------------------- /make_toolchain_deb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | function usage { 6 | cat << EOF 7 | usage: $0 package_name version maintainer 8 | EOF 9 | } 10 | 11 | if [[ "$#" -ne 3 ]]; then 12 | usage 13 | exit 0 14 | fi 15 | 16 | pkgname="$1" 17 | subpkgname="toolchain" 18 | pkgver="$2" 19 | maintainer="$3" 20 | arch="amd64" 21 | 22 | tmpdir="/tmp/$pkgname-$subpkgname-deb-$$" 23 | pkgdir="${tmpdir}/${pkgname}-${subpkgname}_${pkgver}_${arch}" 24 | srcdir="." 25 | 26 | DEBIAN_CONTROL="Package: %s 27 | Version: %s 28 | Section: devel 29 | Priority: optional 30 | Architecture: $arch 31 | Depends: adbi (>= 3.0) 32 | Installed-Size: %s 33 | Maintainer: %s 34 | Homepage: http://adbi.sprc.samsung.pl 35 | Description: Sample toolchain for ADBI tool 36 | Sample toolchain for Android Dynamic Binary Instumentation tool. 37 | " 38 | 39 | DEBIAN_POSTINST="7z x -bd \"/usr/share/$pkgname/toolchain.7z\" -o\"/usr/share/$pkgname/\"" 40 | DEBIAN_POSTRM="rm -rf /usr/share/$pkgname/toolchain" 41 | 42 | DEBIAN_CHANGELOG="$pkgname$pkgsubname (${pkgver%-*}) UNRELEASED; urgency=medium 43 | 44 | * Initial release. 45 | 46 | -- ASDD Team Thu, 25 Sep 2014 14:20:02 +0200" 47 | 48 | echo "Packaging..." 49 | 50 | install -m 644 -D "$srcdir/COPYRIGHT" "$pkgdir/usr/share/doc/$pkgname-$subpkgname/copyright" 51 | echo "$DEBIAN_CHANGELOG" > "$pkgdir/usr/share/doc/$pkgname-$subpkgname/changelog.Debian" 52 | gzip --best "$pkgdir/usr/share/doc/$pkgname-$subpkgname/changelog.Debian" 53 | chmod 644 "$pkgdir/usr/share/doc/$pkgname-$subpkgname/changelog.Debian.gz" 54 | 55 | install -m 755 -d "$pkgdir/usr/share/$pkgname" 56 | install -m 644 "$srcdir/toolchain.7z" "$pkgdir/usr/share/$pkgname/toolchain.7z" 57 | 58 | 59 | size=$(du -s "$pkgdir" | cut -f 1) 60 | install -m 755 -d "$pkgdir/DEBIAN" 61 | printf "$DEBIAN_CONTROL" "$pkgname-$subpkgname" "$pkgver" "$size" "$maintainer" > "$pkgdir/DEBIAN/control" 62 | echo "$DEBIAN_POSTINST" > "$pkgdir/DEBIAN/postinst" 63 | echo "$DEBIAN_POSTRM" > "$pkgdir/DEBIAN/postrm" 64 | 65 | chmod 0755 "$pkgdir/DEBIAN/postinst" 66 | chmod 0755 "$pkgdir/DEBIAN/postrm" 67 | 68 | fakeroot dpkg-deb -Z gzip --build "$pkgdir" 69 | 70 | lintian -i "${pkgdir}.deb" 71 | 72 | #dpkg-sig -k 0B233A0C --sign builder "${pkgdir}.deb" 73 | 74 | mv "${pkgdir}.deb" . 75 | 76 | rm -rf $pkgdir 77 | rmdir "$tmpdir" 78 | -------------------------------------------------------------------------------- /process/linker.h: -------------------------------------------------------------------------------- 1 | #ifndef LINKER_H 2 | #define LINKER_H 3 | 4 | void linker_attach(thread_t * thread); 5 | void linker_detach(thread_t * thread); 6 | void linker_reset(thread_t * process); 7 | 8 | void linker_fork(process_t * child, process_t * parent); 9 | 10 | void linker_notify(thread_t * thread); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /process/list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H_ 2 | #define LIST_H_ 3 | 4 | #include "process.h" 5 | #include "thread.h" 6 | 7 | process_t * process_get(pid_t pid) __attribute__((warn_unused_result)); 8 | process_t * process_put(process_t * process); 9 | process_t * process_dup(process_t * process); 10 | 11 | void process_add(process_t * process); 12 | void process_del(process_t * process); 13 | 14 | thread_t * thread_get(pid_t pid) __attribute__((warn_unused_result)); 15 | thread_t * thread_put(thread_t * thread); 16 | thread_t * thread_dup(thread_t * thread); 17 | 18 | void thread_add(thread_t * thread); 19 | void thread_del(thread_t * thread); 20 | 21 | typedef void (process_callback_t)(process_t *); 22 | #define process_lambda(process, ...) ({ void $(process_t * process) { __VA_ARGS__ } $; }) 23 | 24 | void process_iter(void (fn)(process_t *)); 25 | void thread_iter(process_t * process, void (fn)(thread_t *)); 26 | 27 | thread_t * thread_any_running(process_t * process) __attribute__((warn_unused_result)); 28 | thread_t * thread_any_stopped(process_t * process) __attribute__((warn_unused_result)); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /process/process.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCESS_H 2 | #define PROCESS_H 3 | 4 | #include 5 | #include "tree.h" 6 | 7 | typedef struct thread_t thread_t; 8 | typedef struct injectable_t injectable_t; 9 | 10 | typedef struct process_t { 11 | 12 | /* Process PID */ 13 | pid_t pid; 14 | 15 | tree_t threads; 16 | tree_t segments; 17 | tree_t injections; /* (injectable_t *) -> (address_t) */ 18 | tree_t jumps; 19 | 20 | /* Address of linker breakpoint (if installed). */ 21 | struct { 22 | address_t bkpt; /* runtime address */ 23 | insn_t insn; /* original instruction */ 24 | insn_kind_t kind; /* instruction kind */ 25 | } linker; 26 | 27 | refcnt_t references; 28 | 29 | bool mode32; /* 32-bit execution mode? */ 30 | 31 | bool stabilizing; /* are we currently stabilizing threads of the process? */ 32 | bool spawned; /* was the process spawned by us? */ 33 | 34 | } process_t; 35 | 36 | void process_free(process_t * process); 37 | 38 | process_t * process_spawn(const char * argv[]); 39 | process_t * process_attach(pid_t pid); 40 | 41 | void process_kill(process_t * process); 42 | void process_detach(process_t * process); 43 | void process_detach_all(); 44 | void process_cleanup(); 45 | 46 | void process_continue(process_t * process); 47 | void process_stop(process_t * process); 48 | 49 | void process_continue_all(); 50 | void process_stop_all(); 51 | 52 | bool process_is_stopped(process_t * process); 53 | bool process_is_running(process_t * process); 54 | 55 | thread_t * process_pick_stopped_thread(process_t * process); 56 | thread_t * process_pick_running_thread(process_t * process); 57 | 58 | int process_translate_file_to_mem(process_t * process, char * filename, address_t offset, 59 | address_t * address); 60 | int process_translate_mem_to_file(process_t * process, address_t address, char ** filename, 61 | address_t * offset); 62 | 63 | int process_is_adbi_address(process_t * process, address_t address); 64 | 65 | address_t process_mem_alloc(process_t * process, unsigned int size); 66 | int process_mem_free(process_t * process, address_t address); 67 | 68 | process_t * process_forked(process_t * parent, pid_t child_pid); 69 | 70 | void process_stabilize(process_t * process); 71 | 72 | void process_attach_injectable(process_t * process, const injectable_t * injectable); 73 | void process_detach_injectable(process_t * process, const injectable_t * injectable); 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /process/spawn.h: -------------------------------------------------------------------------------- 1 | #ifndef SPAWN_H_ 2 | #define SPAWN_H_ 3 | 4 | #include 5 | 6 | bool spawn_is_spawned(pid_t pid); 7 | void spawn_died(pid_t); 8 | pid_t spawn_process(const char * const * argv); 9 | 10 | #endif /* SPAWN_H_ */ 11 | -------------------------------------------------------------------------------- /process/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | 4 | #include 5 | #include "tree.h" 6 | #include "procutil/ptrace.h" 7 | 8 | struct process_t; 9 | typedef struct process_t process_t; 10 | 11 | typedef struct thread_t { 12 | struct process_t * process; 13 | pid_t pid; 14 | 15 | struct { 16 | bool running; /* is the thread running? */ 17 | bool slavemode; /* is the thread is doing slave work for adbi server? */ 18 | bool execed; /* is was the last stop caused by an exec? */ 19 | bool stopme; /* are we planning to stop the thread? */ 20 | int signo; /* signal to be deliver on next continue */ 21 | bool setoptions; /* do we need to set ptrace options? */ 22 | bool dead; /* is the thread dead? */ 23 | } state; 24 | 25 | bool notified; /* was new thread handlers triggered? */ 26 | 27 | refcnt_t references; 28 | 29 | } thread_t; 30 | 31 | bool thread_is_mode32(thread_t * thread); 32 | 33 | thread_t * thread_create(process_t * process, pid_t pid); 34 | void thread_free(thread_t * thread); 35 | 36 | void thread_continue(thread_t * thread, int signo); 37 | void thread_continue_or_stop(thread_t * thread, int signo); 38 | void thread_stop(thread_t * thread); 39 | 40 | thread_t * thread_attach(process_t * process, pid_t pid); 41 | void thread_detach(thread_t * thread); 42 | void thread_kill(thread_t * thread); 43 | 44 | void thread_exec(thread_t * thread); 45 | void thread_exit(thread_t * thread); 46 | bool thread_trap(thread_t * thread); 47 | 48 | bool thread_get_regs(thread_t * thread, pt_regs * regs); 49 | bool thread_set_regs(thread_t * thread, pt_regs * regs); 50 | 51 | void thread_wait(thread_t * thread, bool nohang); 52 | 53 | bool thread_check_alive(thread_t * thread); 54 | 55 | bool thread_is_stable(thread_t * thread); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /procutil/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef ELF_H_ 2 | #define ELF_H_ 3 | 4 | struct thread_t; 5 | 6 | bool elf_is_elf64(FILE * file); 7 | void * elf_get_local_linker_breakpoint_address(); 8 | void * elf_get_remote_linker_breakpoint_address(struct thread_t * thread); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /procutil/mem.h: -------------------------------------------------------------------------------- 1 | #ifndef MEM_H_ 2 | #define MEM_H_ 3 | 4 | #include /* for size_t */ 5 | 6 | typedef struct thread_t thread_t; 7 | 8 | size_t mem_write(thread_t * thread, address_t address, size_t size, void * data); 9 | size_t mem_read(thread_t * thread, address_t address, size_t count, void * data); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /procutil/procfs.h: -------------------------------------------------------------------------------- 1 | #ifndef PROCFS_H 2 | #define PROCFS_H 3 | 4 | #include 5 | 6 | typedef struct segment_t segment_t; 7 | typedef struct thread_t thread_t; 8 | 9 | pid_t procfs_get_tgid(pid_t pid); 10 | pid_t procfs_get_ppid(pid_t pid); 11 | pid_t procfs_get_tracerpid(pid_t pid); 12 | 13 | bool procfs_iter_threads(pid_t pid, void (fn)(pid_t tid)); 14 | 15 | char procfs_pid_state(pid_t pid, pid_t tid); 16 | 17 | bool procfs_iter_segments(const thread_t * thread, void (fn)(const segment_t * segment)); 18 | 19 | size_t procfs_mem_read(thread_t * thread, address_t offset, size_t size, void * out); 20 | 21 | bool procfs_address_executable(const thread_t * thread, address_t address); 22 | 23 | const char * procfs_get_exe(pid_t pid, pid_t tid); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /procutil/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifndef PTRACE_H 2 | #define PTRACE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "process/process.h" 8 | 9 | #define is_word_aligned(addr) (((addr) & 0x03) == 0) 10 | 11 | bool ptrace_signal(pid_t pid, pid_t tid, int signo); 12 | 13 | bool ptrace_attach(pid_t pid, pid_t tid); 14 | bool ptrace_detach(pid_t pid); 15 | 16 | int ptrace_stop(pid_t pid); 17 | 18 | int ptrace_wait_single(pid_t pid, int * signo); 19 | 20 | bool ptrace_mem_write(pid_t pid, address_t address, unsigned long data); 21 | bool ptrace_mem_read(pid_t pid, address_t address, unsigned long * __restrict data); 22 | 23 | void ptrace_set_options(pid_t pid); 24 | pid_t ptrace_get_child_pid(pid_t pid); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /procutil/tgkill.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include /* For SYS_xxx definitions */ 4 | 5 | #include "tgkill.h" 6 | 7 | #ifndef SYS_tgkill 8 | #define SYS_tgkill __NR_tgkill 9 | #endif 10 | 11 | int tgkill(int tgid, int tid, int sig) { 12 | return syscall(SYS_tgkill, tgid, tid, sig); 13 | } 14 | -------------------------------------------------------------------------------- /procutil/tgkill.h: -------------------------------------------------------------------------------- 1 | #ifndef TGKILL_H_ 2 | #define TGKILL_H_ 3 | 4 | int tgkill(int tgid, int tid, int sig); 5 | 6 | #endif /* TGKILL_H_ */ 7 | -------------------------------------------------------------------------------- /procutil/wait.h: -------------------------------------------------------------------------------- 1 | #ifndef WAIT_H 2 | #define WAIT_H 3 | 4 | void wait_main(); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /tracepoint/jump.c: -------------------------------------------------------------------------------- 1 | #include "process/process.h" 2 | #include "process/segment.h" 3 | #include "jump.h" 4 | 5 | void jump_install(process_t * process, address_t from, address_t to) { 6 | debug("Installing jump in process %s: %s -> %s.", str_process(process), str_address(process, from), 7 | str_address(process, to)); 8 | tree_insert(&process->jumps, (tree_key_t) from, (void *) to); 9 | } 10 | 11 | void jump_uninstall(process_t * process, address_t from) { 12 | debug("Removing jump in process %s at address %s.", str_process(process), str_address(process, from)); 13 | tree_remove(&process->jumps, from); 14 | } 15 | -------------------------------------------------------------------------------- /tracepoint/jump.h: -------------------------------------------------------------------------------- 1 | #ifndef JUMP_H_ 2 | #define JUMP_H_ 3 | 4 | #include "process/process.h" 5 | #include "tree.h" 6 | 7 | void jump_install(process_t * process, address_t from, address_t to); 8 | void jump_uninstall(process_t * process, address_t from); 9 | 10 | static inline address_t jump_get(process_t * process, address_t where) { 11 | return (address_t) tree_get(&process->jumps, (tree_key_t) where); 12 | } 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /tracepoint/patch.h: -------------------------------------------------------------------------------- 1 | #ifndef PATCH_H_ 2 | #define PATCH_H_ 3 | 4 | typedef struct thread_t thread_t; 5 | 6 | bool patch_insn(thread_t * thread, address_t address, insn_kind_t kind, insn_t insn); 7 | bool patch_read_insn(thread_t * thread, address_t address, insn_t * insn, insn_kind_t kind); 8 | bool patch_read_insn_detect_kind(thread_t * thread, address_t address, insn_t * insn, insn_kind_t * kind); 9 | void patch_breakpoint(thread_t * thread, address_t address, insn_kind_t kind); 10 | void patch_relative_jump(thread_t * thread, address_t insn_address, address_t jump_address, insn_kind_t kind); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /tracepoint/template.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "template.h" 4 | 5 | template_instance_t * template_instatiate(const template_t * t) { 6 | template_instance_t * result = adbi_malloc(sizeof(template_instance_t)); 7 | 8 | result->size = t->bindata.size; 9 | result->data = adbi_malloc(t->bindata.size); 10 | 11 | memcpy(result->data, t->bindata.data, t->bindata.size); 12 | 13 | return result; 14 | } 15 | 16 | void template_instance_free(template_instance_t * i) { 17 | free(i->data); 18 | free(i); 19 | } 20 | 21 | 22 | static void template_insert_bits(template_instance_t * instance, 23 | offset_t offset, 24 | const void * data, 25 | const void * mask, 26 | size_t count) { 27 | 28 | const unsigned char * d = data; 29 | const unsigned char * m = mask; 30 | unsigned char * p = instance->data + offset; 31 | 32 | assert(offset >= 0); 33 | assert((offset_t) instance->size > offset); 34 | assert((offset_t) instance->size >= offset + (offset_t) count); 35 | 36 | while (count) { 37 | *p = (*p & ~*m) | (*d & *m); 38 | --count; 39 | ++p; 40 | ++m; 41 | ++d; 42 | } 43 | 44 | } 45 | 46 | static void template_insert_bytes(template_instance_t * i, 47 | offset_t offset, const void * data, size_t count) { 48 | assert((offset_t) i->size > offset); 49 | assert((offset_t) i->size >= offset + (offset_t) count); 50 | memcpy(i->data + offset, data, count); 51 | } 52 | 53 | void template_insert_u16(template_instance_t * instance, offset_t offset, uint16_t value) { 54 | template_insert_bytes(instance, offset, &value, sizeof(uint16_t)); 55 | } 56 | 57 | void template_insert_u16_bits(template_instance_t * instance, offset_t offset, uint16_t value, 58 | uint16_t mask) { 59 | template_insert_bits(instance, offset, &value, &mask, sizeof(uint16_t)); 60 | } 61 | 62 | void template_insert_u32(template_instance_t * instance, offset_t offset, uint32_t value) { 63 | template_insert_bytes(instance, offset, &value, sizeof(uint32_t)); 64 | } 65 | 66 | void template_insert_u32_bits(template_instance_t * instance, offset_t offset, uint32_t value, 67 | uint32_t mask) { 68 | template_insert_bits(instance, offset, &value, &mask, sizeof(uint32_t)); 69 | } 70 | 71 | void template_insert_u64(template_instance_t * instance, offset_t offset, uint64_t value) { 72 | template_insert_bytes(instance, offset, &value, sizeof(uint64_t)); 73 | } 74 | 75 | void template_insert_u64_bits(template_instance_t * instance, offset_t offset, uint64_t value, 76 | uint64_t mask) { 77 | template_insert_bits(instance, offset, &value, &mask, sizeof(uint64_t)); 78 | } 79 | -------------------------------------------------------------------------------- /tracepoint/template.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATE_H_ 2 | #define TEMPLATE_H_ 3 | 4 | #include 5 | #include 6 | #include "util/bindata.h" 7 | 8 | #include "template_field.h" 9 | 10 | typedef struct template_field_t { 11 | template_field_id_t field; 12 | offset_t offset; 13 | } template_field_t; 14 | 15 | typedef struct template_t { 16 | bindata_t bindata; 17 | template_field_t * fields; 18 | const char * name; 19 | offset_t literal_pool; 20 | } template_t; 21 | 22 | extern template_t handler_template_arm; 23 | extern template_t handler_template_thumb; 24 | 25 | typedef bindata_t template_instance_t; 26 | 27 | void template_insert_data(template_instance_t * instance, offset_t offset, const void * data, size_t count); 28 | 29 | void template_insert_u16(template_instance_t * instance, offset_t offset, uint16_t value); 30 | void template_insert_u32(template_instance_t * instance, offset_t offset, uint32_t value); 31 | void template_insert_u64(template_instance_t * instance, offset_t offset, uint64_t value); 32 | 33 | void template_insert_u16_bits(template_instance_t * instance, offset_t offset, uint16_t value, uint16_t mask); 34 | void template_insert_u32_bits(template_instance_t * instance, offset_t offset, uint32_t value, uint32_t mask); 35 | void template_insert_u64_bits(template_instance_t * instance, offset_t offset, uint64_t value, uint64_t mask); 36 | 37 | template_instance_t * template_instatiate(const template_t * t); 38 | void template_instance_free(template_instance_t * i); 39 | 40 | const template_t * template_select(insn_t insn, insn_kind_t kind); 41 | 42 | template_instance_t * template_get_handler(const template_t * template, address_t trampoline_address, address_t insn_address, 43 | address_t handler_address, insn_t insn, insn_kind_t insn_kind); 44 | 45 | bool template_need_return_jump(const template_t * template); 46 | insn_kind_t template_get_template_kind(const template_t * template); 47 | 48 | typedef void (*template_return_callback_t)(address_t from, address_t to); 49 | 50 | void template_iter_return_address(address_t pc, insn_t insn, insn_kind_t kind, const template_t * template, 51 | address_t trampoline_addr, template_return_callback_t callback); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /tracepoint/tracepoint.h: -------------------------------------------------------------------------------- 1 | #ifndef TRACEPOINT_H_ 2 | #define TRACEPOINT_H_ 3 | 4 | #include "process/segment.h" 5 | #include "injectable/injectable.h" 6 | #include "template.h" 7 | 8 | struct tracepoint_t { 9 | /* runtime address */ 10 | address_t address; 11 | 12 | /* trampoline runtime address */ 13 | address_t trampoline; 14 | 15 | /* handler runtime address */ 16 | address_t handler; 17 | 18 | /* instruction and its kind */ 19 | insn_t insn; 20 | insn_kind_t insn_kind; 21 | 22 | /* handler template */ 23 | const template_t * template; 24 | }; 25 | 26 | typedef struct tracepoint_t tracepoint_t; 27 | 28 | void tracepoints_init(thread_t * thread, segment_t * segment); 29 | void tracepoints_gone(thread_t * thread, segment_t * segment); 30 | 31 | void tracepoints_reset(segment_t * segment); 32 | void tracepoints_detach(thread_t * thread, segment_t * segment); 33 | void tracepoints_fork(segment_t * child, const segment_t * parent); 34 | 35 | bool tracepoints_any_defined(const segment_t * segment, const injectable_t * injectable); 36 | 37 | const tracepoint_t * tracepoint_get_by_trampoline_address(const segment_t * segment, address_t address); 38 | const tracepoint_t * tracepoint_get_by_runtime_address(const process_t * process, address_t address); 39 | 40 | #endif /* TRACEPOINT_H_ */ 41 | -------------------------------------------------------------------------------- /unused-syms: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from argparse import ArgumentParser 5 | from collections import defaultdict 6 | from os import path 7 | import subprocess 8 | import sys 9 | 10 | __author__ = 'Michał Leśniewski' 11 | __contact__ = 'm.lesniewski@samsung.com' 12 | __version__ = '0.1' 13 | 14 | def process_file(readelf, file): 15 | cmd = [readelf, '-s', '-W', file] 16 | 17 | imports, exports = set(), set() 18 | 19 | for line in subprocess.check_output(cmd).split('\n'): 20 | try: 21 | num, val, size, type, bind, vis, ndx, name = line.split() 22 | 23 | if bind != 'GLOBAL': 24 | continue 25 | 26 | num = int(num[:-1]) 27 | val = int(val, 16) 28 | size = int(size) 29 | 30 | if ndx == 'UND': 31 | imports.add(name) 32 | else: 33 | exports.add(name) 34 | 35 | except ValueError: 36 | pass 37 | 38 | return imports, exports 39 | 40 | 41 | def main(): 42 | parser = ArgumentParser(description='Find unreferenced global symbols in a set of object files.') 43 | parser.add_argument('--check', type=str, nargs='*', default=[], help='only print symbols from the given file') 44 | parser.add_argument('--ignore', type=str, nargs='*', default=['main'], help='ignore the given symbols (by default only main is ignored)') 45 | parser.add_argument('--readelf', type=str, nargs='?', default='readelf', help='specify readelf path') 46 | parser.add_argument('input', type=str, nargs='+', help='object file') 47 | 48 | args = parser.parse_args() 49 | 50 | ignore = set(args.ignore) 51 | exportmap = defaultdict(list) 52 | exported, imported = set(), set() 53 | 54 | # Use nicely formatted paths 55 | files = [path.relpath(path.normpath(f)) for f in args.input] 56 | check = [path.relpath(path.normpath(f)) for f in args.check] 57 | 58 | if check: 59 | check = [x for x in check if x in files] 60 | else: 61 | check = files 62 | 63 | for file in files: 64 | try: 65 | i, e = process_file(args.readelf, file) 66 | except (subprocess.CalledProcessError, OSError), e: 67 | print e 68 | sys.exit(-1) 69 | 70 | for s in e: 71 | exportmap[s].append(file) 72 | exported |= e 73 | imported |= i 74 | 75 | total = 0; 76 | unused = sorted(exported - imported - ignore) 77 | 78 | for file in check: 79 | unused_in_file = [x for x in unused if file in exportmap[x]] 80 | if not unused_in_file: 81 | continue 82 | total += len(unused_in_file) 83 | print '%s:' % file 84 | for symbol in unused_in_file: 85 | print ' %s' % symbol 86 | print 87 | print '%i unreferenced symbol%s found.' % (total, '' if total == 1 else 's') 88 | 89 | 90 | if __name__ == '__main__': 91 | try: 92 | main() 93 | except KeyboardInterrupt: 94 | print 95 | print 'Aborted.' -------------------------------------------------------------------------------- /util/bindata.h: -------------------------------------------------------------------------------- 1 | #ifndef BINDATA_H 2 | #define BINDATA_H 3 | 4 | #include 5 | 6 | struct bindata_t { 7 | size_t size; 8 | unsigned char * data; 9 | }; 10 | 11 | typedef struct bindata_t bindata_t; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /util/bitops.h: -------------------------------------------------------------------------------- 1 | /* Bit manipulation functions. 2 | * 3 | * Note: Many of the functions defined here use approaches from the excellent "Bit Twiddling Hacks" website by 4 | * Sean Eron Anderson. */ 5 | 6 | #ifndef BITOPS_H_ 7 | #define BITOPS_H_ 8 | 9 | typedef uint32_t bitops_t; 10 | #define bitops_bits ((int) (sizeof(bitops_t) * 8)) 11 | 12 | /* Extract bits low:high from value. */ 13 | static inline bitops_t bits(bitops_t value, unsigned int low, unsigned int high) { 14 | assert((low < bitops_bits) && (high < bitops_bits) && (high >= low)); 15 | int bit_count = (1 + high - low) & (bitops_bits - 1); 16 | bitops_t mask = (1 << (bit_count)) - 1; 17 | return (value >> low) & mask; 18 | } 19 | 20 | /* Extract bit n from value. */ 21 | static inline bitops_t bit(bitops_t value, int n) { 22 | return bits(value, n, n); 23 | } 24 | 25 | /* Sign extend given value, msb is the current most significant bit. */ 26 | static inline bitops_t sign_extend(bitops_t value, unsigned int msb) { 27 | assert(msb > 0); 28 | bitops_t mask = 1U << (msb - 1); 29 | value = value & ((1U << msb) - 1); 30 | return (value ^ mask) - mask; 31 | } 32 | 33 | /* Count the number of bits set in value. */ 34 | static inline bitops_t bits_count(bitops_t value) { 35 | bitops_t c; 36 | for (c = 0; value; c++) { 37 | value &= value - 1; // clear the least significant bit set 38 | } 39 | return c; 40 | } 41 | 42 | /* Get the most significant bit set. */ 43 | static inline bitops_t get_msb(bitops_t value) { 44 | bitops_t c = 0; 45 | while (value >>= 1) 46 | ++c; 47 | return c; 48 | } 49 | 50 | /* Shift the bits of the given value into the bits inside the mask. 51 | * 52 | * Example: 53 | * mask 10110011 54 | * 55 | * [abcde] 56 | * val 10110 57 | * 58 | * [a0bc00de] 59 | * result 10010010 60 | */ 61 | static inline bitops_t get_bits_by_mask(bitops_t val, bitops_t mask) { 62 | bitops_t ret = 0; 63 | int sh; 64 | for (sh = bitops_bits; sh >= 0; --sh) { 65 | if (mask & (1 << sh)) { 66 | ret <<= 1; 67 | ret |= (val & (1 << sh)) ? 1 : 0; 68 | } 69 | } 70 | return ret; 71 | } 72 | 73 | /* Collect the bits in the mask and construct a single value. This is the inverse of get_bits_by_mask. */ 74 | static inline bitops_t set_bits_by_mask(bitops_t val, bitops_t mask) { 75 | bitops_t ret = 0; 76 | int sh; 77 | for (sh = 0; val; ++sh) { 78 | if (mask & (1 << sh)) { 79 | /* the bit is set */ 80 | ret |= (val & 1) << sh; 81 | val >>= 1; 82 | } 83 | } 84 | return ret; 85 | } 86 | 87 | /* Create a bit mask with the given range of bits lit. */ 88 | static inline bitops_t bit_mask(int low, int high) { 89 | assert(low <= high); 90 | return ((1 << (high - low + 1)) - 1) << low; 91 | } 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /util/capabilities.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "capabilities.h" 6 | 7 | #ifdef USE_CAPABILITIES 8 | 9 | #include 10 | 11 | /* Retrieve the capabilities of the given process. Return non-zero on success. */ 12 | static int caps_get(pid_t pid, cap_user_data_t caps) { 13 | 14 | struct __user_cap_header_struct cap_header; 15 | 16 | cap_header.pid = pid; 17 | cap_header.version = _LINUX_CAPABILITY_VERSION; 18 | 19 | if (capget(&cap_header, caps) < 0) { 20 | error("Error reading capabilities of process %d.", (int) pid); 21 | return 0; 22 | } 23 | 24 | return 1; 25 | } 26 | 27 | /* Retrieve the capabilities of the current process. Returns non-zero on 28 | * success. */ 29 | static int caps_get_current(cap_user_data_t caps) { 30 | return caps_get(getpid(), caps); 31 | } 32 | 33 | /* Return true if the current process has the CAP_SYS_PTRACE capability. */ 34 | static int caps_can_ptrace() { 35 | int res; 36 | 37 | struct __user_cap_data_struct caps; 38 | if (!caps_get_current(&caps)) { 39 | return 0; 40 | } 41 | 42 | res = (caps.effective & (1 << CAP_SYS_PTRACE)) 43 | 44 | debug("We have %spermission to use ptrace.", res ? "", "no "); 45 | return res; 46 | } 47 | 48 | #else 49 | 50 | static int caps_can_ptrace() { 51 | static int warned = 0; 52 | 53 | if (!warned) { 54 | warning("Warning: Capability checking is disabled. Assuming that we " 55 | "have all possible permissions."); 56 | warned = 1; 57 | } 58 | 59 | return 1; 60 | } 61 | 62 | #endif 63 | 64 | int caps_init() { 65 | if (caps_can_ptrace()) 66 | return 1; 67 | else { 68 | fatal("Insufficient permissions to use ptrace (CAP_SYS_PTRACE capability missing)."); 69 | return 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /util/capabilities.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPABILITIES_H 2 | #define CAPABILITIES_H 3 | 4 | int caps_init(); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /util/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | 7 | /* If we fail to allocate memory, just abort. Out of memory errors are so rare 8 | * today, that this shouldn't be a problem. Still, if it occurs, we should at 9 | * least tell the user what happened. */ 10 | void * adbi_malloc(size_t size) { 11 | void * result = malloc(size); 12 | if (unlikely(!result)) { 13 | fprintf(stderr, "Fatal: Failed to allocate %zu bytes of memory.\n", size); 14 | abort(); 15 | } 16 | return result; 17 | } 18 | 19 | void * adbi_realloc(void * ptr, size_t size) { 20 | void * result = realloc(ptr, size); 21 | if (unlikely(!result)) { 22 | fprintf(stderr, "Fatal: Failed to allocate %zu bytes of memory.\n", size); 23 | abort(); 24 | } 25 | return result; 26 | } 27 | 28 | void adbi_bug_(const char * file, int line, const char * function, 29 | const char * fmt, ...) { 30 | 31 | va_list args; 32 | 33 | fprintf(stderr, 34 | "Internal error in function %s at %s:%i:\n\t", 35 | function, file, line); 36 | 37 | 38 | va_start(args, fmt); 39 | vfprintf(stderr, fmt, args); 40 | va_end(args); 41 | 42 | fprintf(stderr, "\n"); 43 | fflush(stderr); 44 | 45 | abort(); 46 | } 47 | -------------------------------------------------------------------------------- /util/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #if 1 5 | /* 6 | * assert corrupts the stack, so it's impossible to debug with gdb after a fail 7 | */ 8 | #undef assert 9 | #define assert adbi_assure 10 | #endif 11 | 12 | /* ADBI uses only one thread. Still, many functions support calls from multiple threads by using thread local storage 13 | * instead of global variables, etc. Use of thread local storage is expensive, so we disable the __thread keyword and 14 | * simply use regular static or global variables. */ 15 | #if 1 16 | #define __thread 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "likely.h" 26 | #include "logger.h" 27 | 28 | /* Macro for marking unused parameters. */ 29 | #define UNUSED(x) (void)(x) 30 | 31 | /* Maximum length of absolute file path. */ 32 | #define MAX_PATH 256 33 | 34 | /* Memory allocation. */ 35 | void * adbi_malloc(size_t size); 36 | void * adbi_realloc(void * ptr, size_t size); 37 | 38 | /* Function for internal error notifications. */ 39 | void adbi_bug_( 40 | const char * file, int line, const char * function, 41 | const char * fmt, ...) 42 | __attribute__((noreturn)); 43 | #define adbi_bug(...) \ 44 | adbi_bug_(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); 45 | 46 | #define adbi_bug_unrechable() \ 47 | adbi_bug_(__FILE__, __LINE__, __FUNCTION__, "Unreachable code reached."); 48 | 49 | #define adbi_assure(cond) \ 50 | if (unlikely(!(cond))) \ 51 | adbi_bug_(__FILE__, __LINE__, __FUNCTION__, "False: %s", # cond); 52 | 53 | #define packed_struct struct __attribute__((__packed__)) 54 | 55 | typedef uint32_t id_t; 56 | 57 | typedef unsigned int refcnt_t; 58 | 59 | #include "arch.h" 60 | 61 | #define UNIMPLEMENTED() warning("Call to unimplemented function %s.", __FUNCTION__); 62 | 63 | #define ADBI_INJECTABLE_NAME "#adbi" 64 | 65 | 66 | #include "util/human.h" 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /util/human.h: -------------------------------------------------------------------------------- 1 | #ifndef HUMAN_H_ 2 | #define HUMAN_H_ 3 | 4 | #define str_fn(what) \ 5 | struct what ## _t; \ 6 | const char * str_ ## what(const struct what ## _t * what); 7 | 8 | str_fn(node) 9 | str_fn(process) 10 | str_fn(thread) 11 | str_fn(injection) 12 | str_fn(injectable) 13 | str_fn(segment) 14 | str_fn(tracepoint) 15 | 16 | const char * str_signal(int signo); 17 | const char * str_address(const struct process_t * process, address_t address); 18 | 19 | #undef str_fn 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /util/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef SIGHANDLERS_H 2 | #define SIGHANDLERS_H 3 | 4 | extern volatile int signal_child; 5 | extern volatile int signal_io; 6 | extern volatile int signal_quit; 7 | extern volatile int signal_disconnected; 8 | extern volatile int signal_alarm; 9 | 10 | int signal_init(); 11 | 12 | void signal_wait(); 13 | void signal_wait_single(int signo, int interruptable); 14 | 15 | void signal_block_int(int block); 16 | 17 | void signal_reset(); 18 | 19 | #endif 20 | --------------------------------------------------------------------------------