====== 概述 ====== * [[wp>Self-modifying code]] * [[wp>Reflection (computer science)]] * [[http://users.elis.ugent.be/~mmadou/home/papers/ih06/anckaert06self.pdf|A Model for Self-Modifying Code]] ====== 範例程式 ====== ===== Assembly ===== ;**************************************************************************** ;**************************************************************************** ;* ;* USING SELF MODIFYING CODE UNDER LINUX ;* ;* written by Karsten Scheibler, 2004-AUG-09 ;* ;**************************************************************************** ;**************************************************************************** global smc_start ;**************************************************************************** ;* some assign's ;**************************************************************************** %assign SYS_WRITE 4 %assign SYS_MPROTECT 125 %assign PROT_READ 1 %assign PROT_WRITE 2 %assign PROT_EXEC 4 ;**************************************************************************** ;* data ;**************************************************************************** section .bss alignb 4 modified_code: resb 0x2000 ;**************************************************************************** ;* smc_start ;**************************************************************************** section .text smc_start: ;calculate the address in section .bss, it must lie on a page ;boundary (x86: 4KB = 0x1000) ;NOTE: In this example obsolete because each segment is page ; aligned and we use it only once, so we know that it is ; aligned to a page boundary, but if you have more than ; one section .bss in your code (or link several objects ; together) you can't be sure about that mov dword ebp, (modified_code + 0x1000) and dword ebp, 0xfffff000 ;change flags of this page to read + write + executable, ;NOTE: On x86 Architecture this call is obsolete, because for ; section .bss PROT_READ and PROT_WRITE are already set. ; PROT_EXEC is on x86 also set if PROT_READ is set, this ; results in rwx for this segment, but this behavior may ; change with appearance of the NX-flag in modern processors mov dword eax, SYS_MPROTECT ; int mprotect(const void *addr, size_t len, int prot); mov dword ebx, ebp ; ebp 存放 bss 段所在頁面開頭的位址 mov dword ecx, 0x1000 mov dword edx, (PROT_READ | PROT_WRITE | PROT_EXEC) int byte 0x80 test dword eax, eax js near smc_error ;execute unmodified code first code1_start: mov dword eax, SYS_WRITE ; ssize_t write(int fd, const void *buf, size_t count); mov dword ebx, 1 mov dword ecx, hello_world_1 code1_mark_1: mov dword edx, (hello_world_2 - hello_world_1) code1_mark_2: int byte 0x80 code1_end: ;copy code snippet from above to our page (address is still in ebp) ; 把 code1 copy 到 bss 段 (ebp)。 ; http://courses.engr.illinois.edu/ece390/archive/fall2001/books/labmanual/inst-ref-movsb.html ; movsb 把 esi 的內容拷貝到 edi,重複 ecx 次。 mov dword ecx, (code1_end - code1_start) mov dword esi, code1_start mov dword edi, ebp cld rep movsb ;append 'ret' opcode to it, so that we can do a call to it mov byte al, [return] ; return label 處放的是 ret 指令 stosb ;change some values in the copied code: start address of the text ;and its length ; ebp 是 bss 段的開頭 mov dword eax, hello_world_2 mov dword ebx, (code1_mark_1 - code1_start) mov dword [ebx + ebp - 4], eax mov dword eax, (hello_world_3 - hello_world_2) mov dword ebx, (code1_mark_2 - code1_start) mov dword [ebx + ebp - 4], eax ;finally call it call dword ebp ; 如果只要展現第一個範例,加上底下這行。否則執行流會執行到不該到的地方。 ; jmp smc_end。 ;copy second example ; 拷貝的同時會更新 esi 和 edi。 mov dword ecx, (code2_end - code2_start) ; 欲拷貝的長度 (byte) mov dword esi, code2_start ; 來源 mov dword edi, ebp ; 目的 (bss 段) rep movsb ; 開始搬移 ;do something real nasty: edi points right after the 'rep stosb' ;instruction, so this will really modify itself ; edi 指向? mov dword edi, ebp add dword edi, (code2_mark - code2_start) ; 去掉此行,輸出應為 ebx: 08h。這裡是將 edi 調整成指向 code2_mark,之後再將 ; code2_mark 後的內容覆寫。 call dword ebp ;modify code in section .text itself endless: ;allow us to write to section .text mov dword eax, SYS_MPROTECT ; int mprotect(const void *addr, size_t len, int prot); mov dword ebx, smc_start and dword ebx, 0xfffff000 mov dword ecx, 0x2000 mov dword edx, (PROT_READ | PROT_WRITE | PROT_EXEC) int byte 0x80 test dword eax, eax js near smc_error ;write message to screen mov dword eax, SYS_WRITE mov dword ebx, 1 mov dword ecx, endless_loop mov dword edx, (hello_world_1 - endless_loop) int byte 0x80 ;here comes the magic, which prevents endless execution ; 將終止程序的代碼 (smc_end) 拷貝到 endless,如此便不會有無窮迴圈。 mov dword ecx, (smc_end_1 - smc_end) mov dword esi, smc_end mov dword edi, endless rep movsb ;do it again jmp short endless ;**************************************************************************** ;* code2 ;**************************************************************************** ;this is the ret opcode we copy above ;and the nop opcode needed by code2 return: ret no_operation: nop ;here some real selfmodifying code, if copied ;to .bss and edi correctly loaded ebx should contain 0x4 instead ;of 0x8 ; http://courses.engr.illinois.edu/ece390/archive/fall2001/books/labmanual/inst-ref-stosb.html code2_start: mov byte al, [no_operation] xor dword ebx, ebx ; 清空 ebx mov dword ecx, 0x04 ; 看要覆寫掉幾個後面的 inc dword ebx。 rep stosb ; 將 al 的內容寫到 edi 所指的地方,重複 ecx 次。 code2_mark: inc dword ebx inc dword ebx inc dword ebx inc dword ebx inc dword ebx inc dword ebx inc dword ebx inc dword ebx ; 如果 edi 沒有被改寫,輸出應為 ebx = 08h call dword [function_pointer] ; 印出 ebx: 04h ret code2_end: align 4 function_pointer: dd write_hex ;**************************************************************************** ;* write_hex ;**************************************************************************** write_hex: mov byte bh, bl shr byte bl, 4 add byte bl, 0x30 cmp byte bl, 0x3a jb short .number_1 add byte bl, 0x07 .number_1: mov byte [hex_number], bl and byte bh, 0x0f add byte bh, 0x30 cmp byte bh, 0x3a jb short .number_2 add byte bh, 0x07 .number_2: mov byte [hex_number + 1], bh mov dword eax, SYS_WRITE mov dword ebx, 1 mov dword ecx, hex_text mov dword edx, 9 int byte 0x80 ret section .data hex_text: db "ebx: " hex_number: db "00h", 10 ;**************************************************************************** ;* some text ;**************************************************************************** endless_loop: db "No endless loop here!", 10 ; 10 代表回車 hello_world_1: db "Hello World!", 10 hello_world_2: db "This code was modified!", 10 hello_world_3: ;**************************************************************************** ;* smc_error ;**************************************************************************** section .text smc_error: xor dword eax, eax ; 清空 eax inc dword eax ; _exit 呼叫號 mov dword ebx, eax ; ebx 為狀態號 int byte 0x80 ;**************************************************************************** ;* smc_end ;**************************************************************************** section .text smc_end: xor dword eax, eax ; 清空 eax xor dword ebx, ebx ; 清空 ebx inc dword eax ; _exit 呼叫號 int byte 0x80 smc_end_1: ;*********************************************** linuxassembly@unusedino.de * NASM=nasm -w+orphan-labels -w+macro-params -w+number-overflow -f elf LD=ld -m elf_i386 -s STRIP=strip -R .note -R .comment RM=rm -f .PHONY: all clean all: smc smc: smc.n ${NASM} -o smc.o smc.n ${LD} -e smc_start -o smc smc.o ${STRIP} smc clean: ${RM} *.bak *~ *.o smc core $ ./smc Hello World! This code was modified! ebx: 04h No endless loop here! * [[http://asm.sourceforge.net/articles/smc.html|Using self modifying code under Linux]] * 切到 sh,再下 ''sh -c "( mkdir smc && cd smc && awk '/^