Linux System Hacking

ndk-build 명령을 실행하면 기본적으로 arm 모드로 컴파일이 되고, Thumb 모드로 컴파일 하고 싶으면 


아래와 같이 Android.mk 파일에 LOCAL_ARM_MODE 로 지정해 주면 된다. arm / thumb 로 지정.





hyunminiuiMBP2:jni hyunmini$ tree

.

├── Android.mk

└── test.c




hyunminiuiMBP2:jni hyunmini$ cat Android.mk 


LOCAL_PATH:=$(call my-dir)

include $(CLEAR_VARS)


LOCAL_MODULE:=test

LOCAL_SRC_FILES:=test.c

LOCAL_ARM_MODE:=thumb


include $(BUILD_EXECUTABLE)





'Linux System Hacking' 카테고리의 다른 글

ARM-Thumb 모드 컴파일 옵션  (0) 2016.02.23
ARM Assembly 정리 - ARM 기본 개념  (0) 2016.02.22
LD_PRELOAD 를 이용한 Hooking  (0) 2014.05.03



ARM Assembly










  • ARM(Advanced Risc Machine)

x86 으로 대표되는 CISC 라인과는 반대인 최근에는 모바일이 대세가 되면서 ARM(RISC) 프로세서도 많이 사용되고 있다. 모바일 점검을 하다 보면 간혹 ARM 리버싱을 하게 되는 일이 있기도 하지만 이미 몇년 전 부터 CTF 에서도 ARM플랫폼 문제가 종종 나오고 있기 때문에 ARM 아키텍쳐에 대해서 정리해 보려 한다.


  • Thumb 모드 / ARM 모드
  ARM 과 x86 의 가장 큰 차이점은 Thumb 모드라는 것이 있다는 것이다. ARM 자체가 모바일/임베디드 등 PC 와는 다른 환경에 맞춰서 설계했기 때문에 저전력이 핵심 기술 중 한가지였고, 또 한가지로 처음 설계될 당시 임베디드 계열에서는 32비트가 아닌 16비트가 대세였다고 한다. 이러한 여러가지 상황에 맞추기 위해 2가지 모드를 지원하게 되었고, 리버싱을 할 때에도 이 부분을 고려해야 한다. 쉘코드를 작성할 때에도 당연히 바이트 수를 줄이기 위해 Thumb 모드로 작성하는 것이 좋다. 

  • ARM 모드
-   레지스터 : R0 ~ R15 (16개)
-   기계어코드 길이 : 32비트 (4바이트)

  • Thumb 모드 

-   레지스터 : R0 ~ R7 (8개)
-   기계어코드 길이 : 16비트 (2바이트)

  • Thumb <-> ARM 모드 전환

-    BLX / BX 등 X 로 끝나는 분기문 명령으로 모드 전환 




  • 레지스터
레지스터는 x86 과 상당한 차이점이 있다. 일단 범용 레지스터의 수가 더 많으며, x86 에는 존재하지 않는 Link Register 가 존재한다.  

  •   R0 ~ R12   :   범용 레지스터, 인자값 및 임시 계산 저장소 등
  •   R13(SP)     :   Stack Pointer, x86 의 ESP 와 비슷한 역할 수행
  •   R14(LR)     :   Link Register, 함수 호출 전 LR 에 리턴 주소를 저장하고 점프함(함수 호출 시 리턴주소 스택 활용 X)
  •   PC              :   x86 에서의  EIP 레지스터와 동일한 역할 수행. 다음에 실행할 코드의 주소 저장



  • Calling Convention(함수 호출 규약)
x86 에서는 cdecl, fastcall, stdcall 등의 다양한 함수 호출규약이 존재했으나, 
  •   R0 ~ R12   :   범용 레지스터, 인자값 및 임시 계산 저장소 등
  •   R13(SP)     :   Stack Pointer, x86 의 ESP 와 비슷한 역할 수행



  • 실습환경
  • NDK 10   :   Android NDK Version.10
  • IDA Pro   :   디스어셈블 및 분석
  • GDB        :   디버깅
  • ARM 장비:  안드로이드 스마트폰(베가 아이언), OS 버전 4.4   


  • 리버싱 기본
  • 예제 소스  :   test.c       //     기본 api 들을 호출하는 간단한 프로그램    


  • 컴파일 :  디버그 정보를 포함하여 컴파일(기본적으로 ndk-build 는 strip 바이너리를 생성함)

  • # ndk-build NDK_DEBUG=1 
  • .

    ├── jni

    │   ├── Android.mk

    │   └── test.c

    ├── libs

    │   └── armeabi

    │       ├── gdb.setup

    │       ├── gdbserver

    │       └── test    //  stripped binary

    └── obj

        └── local

            └── armeabi

                ├── objs

                │   └── test

                │       ├── test.o

                │       └── test.o.d

                ├── objs-debug

                │   └── test

                │       ├── test.o

                │       └── test.o.d

                └── test     //   strip 되기 전의 디버깅 심볼 포함 파일,  이 파일로 디버깅 진행 



  • IDA Pro 디스어셈블링(ARM 모드로 컴파일)




  • 상세분석

;int __cdecl main(int argc, const char  **argv,  const char **envp)

EXPORT main

main ; DATA XREF: _start+4Co .got:main_ptro


f = -0x70

test = -0x6C

var_8 = -8


STMFD SP!, {R11,LR}                  //  R11 과 LR 을 스택에 저장하고 SP 8 감소

ADD R11, SP, #4                             //  SP+4 를 한 뒤 R11 에 저장

SUB SP, SP, #0x70                        //  SP 70 감소                 

LDR R2, =_GLOBAL_OFFSET_TABLE_ ; PIC mode     // GOT 주소를 R2 에 저장

NOP                                              // 아무일도 하지 않음

LDR R3, =(__stack_chk_guard_ptr - 0xAFBC)  // 스택가드 offset 을 R3에 저장

LDR R3, [R2,R3] ; __stack_chk_guard   // GOT+스택가드offset 을 R3 에 저장

LDR R3, [R3]             // R3 주소의 값을 R3 에 저장(스택쿠키)

STR R3, [R11,#var_8]    // R3 값(스택쿠키)을  R11 + var_8 에 저장

SUB R2, R11, #-test      // test 변수

MOV  R3, #0x64

MOV R0, R2 ; s

MOV  R1, #0 ; c

MOV  R2, R3 ; n

BL memset

MOV R3, #0

STR R3, [R11,#f]


loc_8658 ; CODE XREF: main+A0j

SUB R3, R11, #-test

MOV  R0, R3 ; name

MOV R1, #0x28 ; len

BL gethostname

SUB R3, R11, #-test

MOV  R0, R3 ; s

BL puts

LDR R3, =(aTest_txt - 0x8680)

ADD R3, PC, R3 ; "test.txt"

MOV R0, R3 ; file

MOV  R1, #2 ; oflag

BL open

STR R0, [R11,#f]

LDR R0, [R11,#f] ; fd

LDR R3, =(a12345 - 0x869C)

ADD R3, PC, R3 ; "12345\n"

MOV  R1, R3 ; buf

MOV  R2, #6 ; n

BL write

LDR R0, [R11,#f] ; fd

BL close

MOV  R0, #3 ; seconds

BL sleep

B loc_8658

; End of function main


; ---------------------------------------------------------------------------

off_86B8 DCD _GLOBAL_OFFSET_TABLE_ ; DATA XREF: main+Cr

off_86BC DCD __stack_chk_guard_ptr - 0xAFBC ; DATA XREF: main+14r

off_86C0 DCD aTest_txt - 0x8680 ; DATA XREF: main+60r

; "test.txt"

off_86C4 DCD a12345 - 0x869C ; DATA XREF: main+7Cr

; "12345\n"




    • IDA Pro 디스어셈블링(Thumb 모드로 컴파일)
     





 

   

'Linux System Hacking' 카테고리의 다른 글

ARM-Thumb 모드 컴파일 옵션  (0) 2016.02.23
ARM Assembly 정리 - ARM 기본 개념  (0) 2016.02.22
LD_PRELOAD 를 이용한 Hooking  (0) 2014.05.03


# LD_PRELOAD 를 이용한 후킹 



# LD_PRELOAD


프로세스 실행 과정 중 라이브러리를 로딩 할때, LD_PRELOAD 변수가 설정되어 있으면 해당 변수에 지정된

라이브러리를 먼저 로딩하고, 이중 libc 함수명과 동일한 함수가 있다면 해당 함수를 먼저 호출해 준다.

즉, 자동으로 후킹을 수행하도록 해준다는 말과 같다.

참고 - OS 별 PRELOAD 환경변수


Linux : LD_PRELOAD 

AIX : LDR_PRELOAD

Solaris : LD_PRELOAD

FreeBSD : LD_PRELOAD



간단히 개념 정리를 위한 예제를 살펴보자. 


$ ls

secuholic  test1  test2  test3

ls 명령 수행 시 현재 디렉토리의 파일 목록이 보인다. 파일 중 secuholic 이 보이지 않도록 해 본다.


$ ltrace ls

         ...

strcpy(0x08058758, "test1")                       = 0x08058758

readdir64(0x08057720, 0x08057700, 0xbffffb84, 1, 0x0805777c) = 0x08057794

malloc(6)                                         = 0x08058768

strcpy(0x08058768, "test2")                       = 0x08058768

readdir64(0x08057720, 0x08057700, 0xbffffb84, 1, 0x08057794) = 0x080577ac

malloc(6)                                         = 0x08058778

strcpy(0x08058778, "test3")                       = 0x08058778

readdir64(0x08057720, 0x08057700, 0xbffffb84, 1, 0x080577ac) = 0x080577c4

malloc(10)                                        = 0x08058788

strcpy(0x08058788, "secuholic")                   = 0x08058788

readdir64(0x08057720, 0x08057700, 0xbffffb84, 1, 0x080577c4) = 0x080577e0

malloc(7)                                         = 0x08058798

         ...

secuholic  test1  test2  test3



중간 문자열 처리 과정에서 strcpy 함수 호출 시 src 가 secuholic 인지 비교하여 참인 경우 변조를 하면 된다.



$ cat test.c

#include <stdio.h>

#include <string.h>


char *strcpy(char *dest, const char *src)

{

int i =0;

while (src[i] != '\0')

{

dest[i] = src[i];

i++;

}

dest[i] = '\0';

printf("[hooked] : strcpy(%x,\"%s\")\n",dest,src);

return &dest[0];

}





$ LD_PRELOAD=./hook.so ls

[hooked] : strcpy(8054a48,"xterm-redhat")

[hooked] : strcpy(8054c18,"xterm-xfree86")

[hooked] : strcpy(bffffa87,"46")

[hooked] : strcpy(8054a4c,"li#46")

[hooked] : strcpy(bffffa87,"98")

[hooked] : strcpy(8054c1c,"co#98")

[hooked] : strcpy(8054fa0,"no=00:fi=00:di=01;34:ln=")

[hooked] : strcpy(80549b8,".")

[hooked] : strcpy(80549c8,"test1")

[hooked] : strcpy(80549d8,"test2")

[hooked] : strcpy(80549e8,"test3")

[hooked] : strcpy(80549f8,"secuholic")   // secuholic 문자열 복사

[hooked] : strcpy(8054b28,"test.c")

[hooked] : strcpy(8054b38,"hook.so")

hook.so  secuholic  test.c  test1  test2  test3




이제 해당 부분을 수정해 보자.



$ cat test.c


#include 
#include 

char *strcpy(char *dest, const char *src)
{
	int i =0;
      if(strcmp(src,"secuholic")==0){
	     dest[i] = '\0';
	     return &dest[0]; // src가 secuholic 인 경우 바로 리턴
	}
	while (src[i] != '\0')
	{
		dest[i] = src[i];
		i++;
	}
	dest[i] = '\0';
//	printf("[hooked] : strcpy(%x,\"%s\")\n",dest,src);
	return &dest[0];
}



gcc -shared -fPIC -o hook.so test.c


$ ls 

 hook.so secuholic test.c test1 test2 test3   // secuholic 존재


$ LD_PRELOAD=./hook.so ls 

 hook.so test.c test1 test2 test3   //  secuholic 숨김


이렇게 간단히 후킹이 가능함을 확인해 보았다. LD_PRELOAD 는 setuid 가 걸려 있으면 동작하지 않으며, 타인의 프로세스에는 영향을


줄 수 없는 등 몇가지 제한 사항이 있으나, 쉽게 후킹이 가능하다는 점에서 유용하다 볼 수있겠다.  :)



'Linux System Hacking' 카테고리의 다른 글

ARM-Thumb 모드 컴파일 옵션  (0) 2016.02.23
ARM Assembly 정리 - ARM 기본 개념  (0) 2016.02.22
LD_PRELOAD 를 이용한 Hooking  (0) 2014.05.03

+ Recent posts