[root@localhost tcpip]# cat ./ip_client.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <arpa/inet.h>

#include <sys/socket.h>

#include <sys/types.h>

#define BUF_SIZE 1024

void Error_handling(char *message);

 

int main(int argc, char *argv[]){

        int sock;

        char ipinfo[BUF_SIZE];

        struct sockaddr_in serv_addr;

        int recv_len;

 

        if(argc!=3){

                printf("Usage : %s <IP> <PORT> \n",argv[0]);

                exit(1);

        }

 

        sock=socket(PF_INET, SOCK_STREAM, 0);

        if(sock==-1){

                Error_handling("socket() error");

        }

 

        memset(&serv_addr, 0, sizeof(serv_addr));

        serv_addr.sin_family=AF_INET;

        serv_addr.sin_addr.s_addr=inet_addr(argv[1]);

        serv_addr.sin_port=htons(atoi(argv[2]));

 

        if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){

                Error_handling("connect() error");

        }

 

        recv_len=read(sock, ipinfo, BUF_SIZE);

        ipinfo[recv_len]=0;

        printf("My IP Address is %s \n",ipinfo);

        close(sock);

        return 0;

}

 

void Error_handling(char *message){

        fputs(message, stderr);

        fputc('\n',stderr);

        exit(1);

}

[root@localhost tcpip]# cat ./ip_server.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <arpa/inet.h>

#define BUF_SIZE 1024

 

void Error_handling(char *message);

 

int main(int argc, char *argv[]){

        int serv_sock,clnt_sock;

        char ipinfo[BUF_SIZE];

        int clnt_addr_is;

        int i=0;

        struct sockaddr_in serv_addr, clnt_addr;

        socklen_t clnt_addr_size;

 

        if(argc!=2){

                printf("Usage : %s <PORT> \n",argv[0]);

                exit(1);

        }

 

        serv_sock=socket(PF_INET, SOCK_STREAM, 0);

        if(serv_sock==-1){

                Error_handling("socket() error");

        }

        memset(&serv_addr, 0, sizeof(serv_addr));

        serv_addr.sin_family=AF_INET;

        serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);

        serv_addr.sin_port=htons(atoi(argv[1]));

 

        if(bind(serv_sock,(struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){

                Error_handling("bind() error");

        }

        if(listen(serv_sock, 5)==-1){

                Error_handling("listen() error");

        }

 

        clnt_addr_size=sizeof(clnt_addr);

 

        clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_addr, &clnt_addr_size);

        if(clnt_sock==-1){

                Error_handling("accept() error");

        }

        else{

                printf("client IP address is : %s \n",inet_ntoa(clnt_addr.sin_addr));

        }

        write(clnt_sock,inet_ntoa(clnt_addr.sin_addr),sizeof(inet_ntoa(clnt_addr.sin_addr))+1);

        close(clnt_sock);

        close(serv_sock);

}

 

void Error_handling(char *message){

        fputs(message,stderr);

        fputc('\n',stderr);

        exit(1);

}

今までIntelアセンブリ言語だけ見てたけど、armは初めて見たので色々探しながら勉強した。

 

ARMレジスターの整理

R0 ~ R10 : 汎用レジスタ、一般演算及び、臨時セーブ場所等で使用

R11 : Current Stack Frame Pointer、現在関数のフレームポインター

R12 : Intra-Procedure call Scratch Register、臨時データをセーブするサブルーチンに使用

R13 : Stack Pointer(SP)、各動作モードごと別途で存在

R14 : Link Register(LR)、関数を呼び出す時リターンされる住所を持ってる

R15 : Program Counter(PC)、次に実行される命令語を持ってる。メモリから持ってくる

CPSR : Program Status Register(CPSR)、各モードごとに一つ存在し、モードが変更される度に変更される前のCPSRがSPSRにセーブされる

 

CPUアーキテクチャのPIPELINE

1.Fetchはプログラムメモリから命令語をロードする

2.DecodeはInstruction Registerの命令語を解釈する

3.Executeは命令語を処理する

4.Write-Backは処理された結果をレジスター又は、データメモリにセーブする

時間があれば、ARMとかCPUについてもっと勉強しなきゃ。。。

まず、ソースコードを見てみる

回答はkey1+key2+key3の値を入れればflagが出力されるようだ。

では、key1から見てみる

<+8>の部分でpcをr3に入れてr0にまた入れることが見える。(r0はリターンの値)

ここでpcはFetchを指している。(32bit基準+8)

なので、0x8ce4という事になる。

次はkey2を見てみる

add r6, pc, #1

bx r6部分でthumb modeに変更される。

thumb modeでのpcは最近の住所に+4がセーブされる。

なので、0x8d04 + 4になるし

adds r3, #4で+4になるので

0x8d04 + 4 +4 = 0x8D0Cという事になる

最後にkey3を見てみると

ここもr0にr3をいれるので、r3を追跡してみるとlrという値があるが

これはr14で関数を呼び出す時リターンされる住所を持ってる

つまり、main関数で呼び出したので、main関数を見なければいけない

なので、0x8d80という事になる。

key1+key2+key3を全部足して10進数に変換すると

0x8ce4 + 0x8d0c + 0x8d80 = 0x1A770 = 108400になる

成功!!

#include <"違う例のヘッダーと同じ">

#define BUF_SIZE 1024

#define OPSZ 4

void error_handling(char *message);

int calculate(int opnum, int opnds[], char oprator);

 

int main(int argc, char *argv[]){

int serv_sock, clnt_sock;

char opinfo[BUF_SIZE];

int result, opnd_cnt, i;

int recv_cnt, recv_len;

struct sockaddr_in serv_addr, clnt_addr;

socklen_t clnt_addr_sz;

 

if(argc!=2){

printf("Usage : %s <port>\n", argv[0]);

exit(1);

}

 

serv_sock=socket(PF_INET, SOCK_STREAM, 0);

if(serv_sock==-1){

error_handling("socket() error");

}

 

memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

serv_addr.sin_port = htons(atoi(argv[1]));

 

if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){

error_handling("bind() error");

}

if(listen(serv_sock, 5)==-1){

error_handling("listen() error");

}

clnt_addr_sz = sizeof(clnt_addr);

 

/* 五つのクライアントにサービスを提供するための繰り返し文 */

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

{

opnd_cnt = 0;

clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_sz);

/* 一番最初にオペランドの数を受信している */

read(clnt_sock, &opnd_cnt, 1);

 

recv_len = 0;

/* 確認したオペランドの数を元にオペランドを受信している */

while((opnd_cnt*OPSZ+1) > recv_len)

{

recv_cnt = read(clnt_sock, &opinfo[recv_len], BUF_SIZE-1);

recv_len+=recv_cnt;

}

/* calculate関数を呼び出しながら、オペランドの情報と演算子の情報を引数として渡している */

result = calculate(opnd_cnt, (int*)opinfo, opinfo[recv_len-1]);

/* calculate関数がリターンした演算結果をクライアントに転送している */

write(clnt_sock, (char*)&result, sizeof(result));

close(clnt_sock);

}

close(serv_sock);

return 0;

}

 

int calculate(int opnum, int opnds[], char op){

int result=opnds[0], i;

switch(op)

{

case '+':

for(i = 1; i < opnum; i++) result+=opnds[i];

break;

case '-':

for(i = 0; i < opnum; i++) result-=opnds[i];

break;

case '*':

for(i = 0; i < opnum; i++) result*=opnds[i];

}

return result;

}

 

void error_handling(char *message){

/* 違う例のerror_handling関数と同じ */

}

#include <"違う例のヘッダーと同じ">

#define BUF_SIZE 1024

#define RLT_SIZE 4

#define OPSZ 4

void error_handling(char *message);

 

int main(int argc, char *argv[]){

int sock;

char opmsg[BUF_SIZE];

int result, opnd_cnt, i;

struct sockaddr_in serv_addr;

if(argc!=3){

printf("Usage : %s <IP> <PORT>\n",argv[0]);

exit(1);

}

 

sock=socket(PF_INET, SOCK_STREAM, 0);

if(sock==-1){

error_handling("socket() error");

}

memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr.sin_family=AF_INET;

serv_addr.sin_addr.s_addr=inet_addr(argv[1]);

serv_addr.sin_port=htons(atoi(argv[2]));

 

if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){

error_handling("Connect() error");

}

else{

printf("Connected……");

}

 

fputs("Operand count : ", stdout);

/* 使用者からオペランドの数を入力してもらって、opmsg配列にセーブする。char系での型変換は”オペランドの数情報を1バイト整数型で伝達する”と定義したプロトコルだとする。 */

scanf("%d", &opnd_cnt);

opmsg[0] = (char)opnd_cnt;

 

/* 使用者から整数を入力してもらって、opmsg配列にセーブする。char型配列にint型整数をセーブしなきゃいけないので、int型ポインターに型変換してる */

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

{

printf("Operand %d : ", i+1);

scanf("%d", (int*)&opmsg[i * OPSZ+1]);

}

/* この後 scanf()で文字を入力されるが、バッファーに残っている\nを削除するためfgetc関数を呼び出す */

fgetc(stdin);

fputs("Operator : ", stdout);

/* 最後に演算子情報を入力され、opmsg配列にセーブする */

scanf("%c", &opmsg[opnd_cnt*OPSZ+1]);

/* write関数を呼び出して、opmsgにセーブされている演算関連情報を一気に転送している。複数のwrite関数を呼び出して、転送してもいいなぜなら、TCPにはデータのバウンダリーが存在しないため */

write(sock, opmsg, opnd_cnt*OPSZ+2);

/* サーバが転送してくれる演算結果をセーブして出力する */

read(sock, &result, RLT_SIZE);

printf("Operation result : %d \n", result);

close(sock);

return 0;

}

 

void error_handling(char *message){

/* 違う例のerror_handling関数と同じ */

}