|
[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関数と同じ */ } |





