我的解题过程
-
拖入ExeInfo,查看无壳
- NOT Win EXE - .o - ELF executable [ 64bit obj. Exe file - CPU : AMD x86-64 - OS/ABI: unspecified ]
- -> Compiler : GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
-
直接拖入IDA进行分析,可以直接看到main函数,反汇编代码如下
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) { size_t v3; // rsi int i; // [rsp+3Ch] [rbp-54h] char s[36]; // [rsp+40h] [rbp-50h] int v6; // [rsp+64h] [rbp-2Ch] __int64 v7; // [rsp+68h] [rbp-28h] char v8[8]; // [rsp+70h] [rbp-20h] int v9; // [rsp+8Ch] [rbp-4h] v9 = 0; strcpy(v8, ":\"AL_RT^L*.?+6/46"); v7 = 28537194573619560LL; v6 = 7; printf("Welcome to the RC3 secure password guesser.\n", a2, a3); printf("To continue, you must enter the correct password.\n"); printf("Enter your guess: "); __isoc99_scanf((__int64)"%32s", (__int64)s); v3 = strlen(s); if ( v3 < strlen(v8) ) wrong(); for ( i = 0; i < strlen(s); ++i ) { if ( i >= strlen(v8) ) wrong(); if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) ) wrong(); } success(); }
- 首先输入字符串长度要大于v8长度,如果小于则回显错误并退出程序
- 接下来循环检测s的每一个字符,当i大于v8长度时报错,所以s长度要和v8长度一致
- v7初始为int64类型的28537194573619560LL,后来使用(_BYTE *)&v7取v7的地址所为指向BYTE型数据的指针,所以v7被看作BYTE类型的数组
- (_BYTE *)&v7 + i % v6是移动指针,因为v6为常量7,所以使用了int64的前七个BYTE
- (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )是把v7[i]与v8[i]进行按位或,之后作为char类型数据,与s[i]进行比较,如果相同则通过测试
-
简化反汇编程序,如下:
int mian(){ char[8] v8; strcpy(v8, ":\"AL_RT^L*.?+6/46"); char[8] v7 = (char *)28537194573619560LL; char[8] s; printf("Welcome to the RC3 secure password guesser.\n"); printf("To continue, you must enter the correct password.\n"); printf("Enter your guess: "); scanf("%s",s);//s和v8一样长 for(int i=0;i<strlen(v8);i++){ if(s[i]!=(char)(v7[i]^v8[i])){ printf("Incorrect password!\n"); return 0; } } printf("You entered the correct password!\nGreat job!\n"); return 0; }
-
第一次解题程序,出现问题
#include<stdio.h> #include<string.h> #include<stdlib.h> int main(){ long long v7=28537194573619560LL; char v8[8]; strcpy(v8,":\"AL_RT^L*.?+6/46"); for(int i=0;i<strlen(v8);++i){ printf("%c",(char)(*((char*)&v7 + i %7 ) ^ v8[i])); } printf("\n"); system("pause"); return 0; } //输出结果为ostd{fc //错误
-
查看writeup后发现问题出在v8的复制上,:
#include<stdio.h> #include<string.h> #include<stdlib.h> int main(){ __int64 v7=28537194573619560LL; //char v8[8]; //strcpy(v8,":\"AL_RT^L*.?+6/46"); char v8[18]=":\"AL_RT^L*.?+6/46"; for(int i=0;i<strlen(v8);++i){ printf("%c",(char)(*(( char *)&v7 + i %7 ) ^ v8[i])); } printf("\n"); system("pause"); return 0; } //输出结果为RC3-2016-XORISGUD //正确
问题出在了v8一开始进行了strcpy,将17字节复制进了v8原有的空间中,造成了缓冲区溢出
-
证明:
#include<stdio.h> #include<string.h> #include<stdlib.h> int main(){ __int64 v7=28537194573619560LL; char v8[8]; strcpy(v8,":\"AL_RT^L*.?+6/46"); printf("%lld\n",v7); printf("\n"); system("pause"); return 0; } //打印了v7为3760283773249137228 //而v8初始就有18B时,v7正确为28537194573619560 //应该是v7在内存中在v8后面,当strcpy时,由于原v8空间不够,占用了v7原有的空间,导致运算出错
独立思考
IDA分析出来的数据长度并不可靠,需要自己进行判断,解题时避免自己出现缓冲区溢出。而且使用n快捷键可以在IDA中重命名函数,但是重命名变量时需要注意。ELF程序不一定要使用IDA远程动态调试,如果没有壳,可以直接在IDA中进行静态分析。
__int64在c语言中是一个数据类型。
BYTE不同于char,而是unsigned char,注意这些细节。