본문 바로가기

reversing/reversing

ARM Handray

SMALL

환경 구축 후, 간단하게 ARM 어셈블리를 살펴보려 한다.

자료를 보니... 백날 봐봤자 지루하기만해서 간단한 프로그램을 어셈으로 보면서 스택, 함수 호출, 리턴 등 관련해서 살펴본다.


사용 TOOL : GDB, IDA 32bit


richong@ubuntu:~$ file HAND 

HAND: ELF 32-bit LSB executable, ARM, version 1, statically linked, for GNU/Linux 2.6.8, not stripped

위와 같은 파일이고 실행하면 더하기랑 간단하게 정보를 출력한다.

[실행 화면]


기본적인 어셈 명령어 및 레지스터

R0 - R10 : 범용 레지스터, 임시 저장 용

R11 : Current SFP(Stack Frame Pointer)

R12 : ARM Mode 와 Thumb Mode 전환 필요 할 때, 접근 가능 range 벗어날 때[쉽게 fall jmp] 때 사용

  추후 좀 더 자세히  Thumb Mode : 16bit, ARM Mode는 32bit Mode

R13 : Stack Pointer(SP)

R14 : Link Register(LR) Func call 했을 때 ret 저장 레지스터

R15 : Program Counter(PC), 다음 실행될 명령어 주소


ADD, SUB, AND, MOV, CMP : Intel과 유사

 ADD R0, R1, R2 --> R0 = R1+R2

 SUB R0, R1, R2 --> R0 = R1 - R2


B : Branch, ARM 환경에서 JMP/CALL과 같다.

BL Address : LR에 돌아 올 장소 저장 후, Address로 이동

BX R0 : R0 레지스터의 값으로 이동

BLX R0 : Thumb mode로 전호나하고 R0 이동


LDR, STR : 메모리에 값을 저장, read 

LDR R1, [R2, R3] = R2+R3에서 Word만큼 읽어서 R1에 저장

R1이 100번지, R2가 200번지, 300번지 값이 7

300번지의 값인 7을 읽어서 R1에 저장

STR R1, [R2,R3]

위의 예시를 사용해서 300번지에 R1의 값을 저장


STMFD, LDMFD

STMFD sp!, {r4,r6, lr} --> r4,r6,lr을 스택에 저장하고 sp 감소

LDMFD sp!, {r4,r6,pc} --> 스택에서 r4,r6 pc 복원하고 sp 증가



--------------------------------------------------------- ARM 명령어 설명 추가 ---------------------------------------------------------

ARM 명령어 정리

명령어에 붙어있는 ! [느낌표]

값의 변경을 유지


LDR 종류 - 자동 인덱스, 프리 인덱스, 포스트 인덱스


자동    인덱스    ex) LDR r0, [r1, #4]!   -> 프리 인덱스의 경우 ! 표시가 첨가되며, base[r1]과 offset인 #4가 메모리 지정 [   ]에 들어감
                                                          -> SRC와 DST의 값에 영향을 끼침
                                                          -> 결과 R0 = mem[R1 + 4], R1 = R1 +4 
                                                          -> R1의 값이 변동되는 것이 특이 사항


프리    인덱스    ex) LDR r0, [r1, #4]    -> base[r1]과 offset인 #4가 메모리 지정 [   ]에 들어감
                                                          -> DST의 값에만 영향을 끼침
                                                          -> 결과 R0 = mem[R1 + 4]
                                                          -> 자동 인덱스와 차이점음 R1의 값이 변경되지 않ㅇ므


포스트 인덱스    ex) LDR r0, [r1], #4  -> offset값이 메모리 지정 [  ]에 들어가지 않음
                                                        -> SRC와 DST에 모두 영향을 미침
                                                       -> 결과 R0 = mem[R1], R1= R1+4 


SWI : Software Interrupt 인자는 R7 레지스터 사용


상수 값 저장

mov r1, #number
ldr   r1 , =number

mov r1, #100
ldr    r1, =100

string:
.name "richong"

ldr r1, =name  [r1에 name의 주소가 들어감]



ARM Mode, Thumb Mode PC 값 
- RISC의 파이프로 인해 

ARM 모드에서는 실행할 주소의 +8 위치가  PC가 됨
Thumb 모드에서는 실행할 주소의 +4 위치가 PC가 됨


다중 레지스터 처리 LDM 명령어
LDM <mode>  R0! {R1 - R7}
STM <mode>  R0! {R1 - R7}

mode 종류
IA  : Increment After
IB  : Increment Before
DA : Decrement After
DB : Decrement Before

----------------------------------
0x0994  |   4
0x0998  |   3
0x099c  |   2
0x1000  |   1                   <- R0
0x1004  |   5
0x1008  |   6
0x100c   |   7
0x1010   |   8
---------------------------------
[ex]
LDMIA R0!, {R1-R3}                --> 명령어 수행 후에  R0  값을 증가 시킨다.
-> R0 를 0x1000으로 가정
-> 결과 = R0 = 0x100c 
R1 = 5
R2 = 6
R3 = 7 
LDMIB R0!, {R1-R3}                    --> 명령어 수행 전에 R0 값을 증가 시킨 후 진행
-> R0 를 0x1000으로 가정
-> 결과 = R0 = 0x100c 
R1 = 6
R2 = 7
R3 = 8


LDM, STM 스택의 조작 

    암 명령어에서 STM<mode>, LDM<mode> 명령어 종류로 스택을 조정함
    그리고 기본적으로 x86에서 push와 pop의 경우 스택의 위, 아래 조정이 기본적으로 정해져있지만.
    암 에서는 선택해줘야함
    
    <mode 종류>
        F[Full]      = 스택 포인터는 마지막으로 사용된 위치의 주소를 가리킨다.
        E[Empty]  = 스택 포인터가 스택의 마지막 아이템 다음의 빈 공간을 가리킴
        A[Ascending]  =  스택 상승
        E[Descending] =  스택 하향
        FA [Full      Ascending  ]     
        FD [Full      Descending]
        EA [Empty Ascending   ]
        ED [Empty Descending ] 

----------------------------------
0x0994  |   4
0x0998  |   3
0x099c  |   2
0x1000  |   1                   <- SP
0x1004  |   5
0x1008  |   6
0x100c   |   7
0x1010   |   8
---------------------------------

[ex]
mov r1,  #10
mov r2, #20
mov r3, #30
mov r4, sp
stmfd r4!, {r1 - r3} 
eor   r1, r1
eor   r2, r2
eor   r3, r3
ldmdb r4, {r1 - r3}



-------------------------------------------------------------------------------------------------------


이렇게 이론적으로 정리하고 분석


먼저 IDA를 통해서 첫부분을 보았다.



.text:000104B0                 STMFD   SP!, {R11,LR}

.text:000104B4                 ADD     R11, SP, #4

.text:000104B8                 SUB     SP, SP, #0x10

.text:000104BC                 MOV     R3, #4

.text:000104C0                 STR     R3, [R11,#var_8]

.text:000104C4                 MOV     R3, #3

.text:000104C8                 STR     R3, [R11,#var_C]

.text:000104CC                 MOV     R3, #0

.text:000104D0                 STR     R3, [R11,#var_10]

.text:000104D4                 LDR     R0, [R11,#var_8]

.text:000104D8                 LDR     R1, [R11,#var_C]

.text:000104DC                 BL      add

.text:000104E0                 STR     R0, [R11,#var_14]

.text:000104E4                 MOV     R0, #0x24       ; size

.text:000104E8                 BL      malloc

.text:000104EC                 MOV     R3, R0

.text:000104F0                 STR     R3, [R11,#var_10]

.text:000104F4                 LDR     R3, [R11,#var_10]

.text:000104F8                 LDR     R1, =aRichong   ; "richong"

.text:000104FC                 MOV     R2, R3

.text:00010500                 MOV     R3, R1

.text:00010504                 LDMIA   R3!, {R0,R1}    ; "richong"

.text:00010508                 STR     R0, [R2]

.text:0001050C                 STR     R1, [R2,#4]

.text:00010510                 LDR     R3, [R11,#var_10]

.text:00010514                 MOV     R2, #0x17

.text:00010518                 STR     R2, [R3,#0x14]

.text:0001051C                 LDR     R3, [R11,#var_10]

.text:00010520                 ADD     R3, R3, #0x18

.text:00010524                 LDR     R2, =a01023456789 ; "01023456789"

.text:00010528                 MOV     R12, R3

.text:0001052C                 MOV     R3, R2

.text:00010530                 LDMIA   R3!, {R0-R2}    ; "01023456789"

.text:00010534                 STR     R0, [R12]

.text:00010538                 STR     R1, [R12,#4]

.text:0001053C                 STR     R2, [R12,#8]

.text:00010540                 LDR     R0, =aHelloArm  ; "Hello ARM!!"

.text:00010544                 BL      puts

.text:00010548                 LDR     R2, [R11,#var_8]

.text:0001054C                 LDR     R3, [R11,#var_C]

.text:00010550                 ADD     R3, R2, R3

.text:00010554                 LDR     R0, =aDDD       ; "%d + %d = %d\n"

.text:00010558                 LDR     R1, [R11,#var_8]

.text:0001055C                 LDR     R2, [R11,#var_C]

.text:00010560                 BL      printf

.text:00010564                 LDR     R1, [R11,#var_10]

.text:00010568                 LDR     R3, [R11,#var_10]

.text:0001056C                 LDR     R2, [R3,#0x14]

.text:00010570                 LDR     R3, [R11,#var_10]

.text:00010574                 ADD     R3, R3, #0x18

.text:00010578                 LDR     R0, =aNameSAgeDCellp ; "name : %s \n age : %d \n cellphone : %s"...

.text:0001057C                 BL      printf

.text:00010580                 MOV     R3, #0

.text:00010584                 MOV     R0, R3

.text:00010588                 SUB     SP, R11, #4

.text:0001058C                 LDMFD   SP!, {R11,PC}

.text:0001058C ; End of function main


GDB를 이용해서 분석과 같이 진행해본다.


IDA를 이용해서 본 어셈블리 부분이 달라 보이긴 하지만 같은 의미이다.


push {r11, lr}

위의 명령이 실행이 되고 스택의 모습

sp-0x4에 존재하는 r11은 main 함수를 호출한 부분의 sp이다.

lrret 주소이다.



add r11, sp, #4

해당 명령어에 의해서 r11에는 sp +0x4의 값이 들어가게 된다.

r11 == sp+0x4


sub sp, sp, #16

sp를 16바이트 만큼 옮겨서 해당 main 함수에서 사용 할 변수의 크기를 할당한다.

아마 0x10[16] 만큼의 공간을 예상 할 수있다.



위와 같이 Frame을 만든다음 r11 레지스터를 이용해서 변수들에 접근을 한다.


MOV     R3, #4              //R3 = 4

STR     R3, [R11,#var_8]  // [R11-8] = R3 = 4

MOV     R3, #3             // R3 = 3

STR     R3, [R11,#var_C] // [R11-0xc] = R3 = 3


int a = 4;

int b = 3;


R3에 값을 저장하고, R11을 이용해서 변수의 값을 셋팅한다.


LDR     R0, [R11,#var_8]  // R0 = [R11-8]

LDR     R1, [R11,#var_C] // R1 = [R11-1212]

BL      add                   // call add


레지스터를 이용해서 인자 값을 전달한다. 

R0에 첫번째 인자를 넣고, 그다음 R1 인자를 전달한다.


add(b,a);


add 함수를 살펴본다.

r11 레지스터를 스택에 저장하고 새로 사용 할 r11을 설정한다. --> add 함수의 frame을 만드는 것

그리고 sp를 12만큼 할당한다.

r11-8 위치에 첫번째 인자인 r0 값을 넣는다.

r11-12 위치에 두번째 인자인 r1의 값을 넣는다.

그리고 r2, r3에 해당 값들을 복사 한후

r3 = r2 + r3를해서 최종 결과 값을 r3에 넣는다.

그리고 return 값을 저장하는 r0에 r3 값을 넣은 후, 해당 함수의 frame을 정리하고

bx lr로 main 함수로 복귀한다.



STR     R0, [R11,#var_14]

MOV     R0, #0x24       ; size

BL      malloc

MOV     R3, R0

STR     R3, [R11,#var_10]


이후, add 함수의 결과 값을 R11-14의 변수에 저장한다. [R11-14] = R0

그리고 malloc을 이용해서 사이즈 0x24만큼 Heap영역을 할당하고 해당 heap 영역의 pointer 값을 

R11-var10에 저장한다.



LDR     R3, [R11,#var_10]                    //Heap Pointer를 R3에 넣음

LDR     R1, =aRichong   ; "richong"      // R1에 Richong 문자열의 pointer 넣음

MOV     R2, R3                                 // R2 = Heap Pointer

MOV     R3, R1                                //  R3 = Richong 문자열 pointer

LDMIA   R3!, {R0,R1}    ; "richong"      // word 단위로 옮기기 때문에 rich은 R0에  ong은 R1에 저장

STR     R0, [R2]                                //R2는 heap pointer 구조체의 첫 주소에 rich 넣는다.

STR     R1, [R2,#4]                            //R1는 heap pointer-4 구조체 영역부터 ong을 넣는다.


위의 명령을 실행 하면서 r0와 r1 값을 보면 실제로 Rich와 ong 문자열이 들어있는 것을 알 수있다.

LDMIA 명령어는 R3에 시작하는 주소로 여러개의 레지스터에 값을 저장 할 때 사용된다.




LDR     R3, [R11,#var_10]        // Heap Poiner

MOV     R2, #0x17                // r2 = 0x17

STR     R2, [R3,#0x14]           // heap pointer +0x14에 0x17 저장

LDR     R3, [R11,#var_10]        //Heap Pointer

ADD     R3, R3, #0x18            // 구조체의 +18 번째 heap pointer  설정

LDR     R2, =a01023456789 ; "01023456789" // r2에 010~ pointer

MOV     R12, R3                    // 구조체 포인터 r12에

MOV     R3, R2                      // R3에 010 POINTER

LDMIA   R3!, {R0-R2}    ; "01023456789"    //R0, R1, R2에 01023465789를 넣는다.

STR     R0, [R12]            // 구조체 포인터에 차레대로 넣는다.

STR     R1, [R12,#4]        //    ==

STR     R2, [R12,#8]        //    ==


위와 같이 구조체를 할당하고 각 내용을 할당 하는 것을 보았다.


그리고 밑에 부분은 print하는 부분이다.


함수 호출 하는 방법과 ret, sfp, struct 이용 관련 어셈을 공부




LIST

'reversing > reversing' 카테고리의 다른 글

MIPS Disassemble  (0) 2017.03.30
MIPS Instruction[Assembly]  (0) 2017.03.29
C++ 리버싱 연습  (0) 2016.11.29
get physical address  (0) 2016.11.29
call[opcode 0xe8] 사용  (0) 2016.11.20