1 #include <stdio.h> 2 #define PASSWORD "1234567" 3 int verify_password (char *password) 4 { 5 int authenticated; 6 char buffer[8]; 7 authenticated=strcmp(password,PASSWORD); 8 strcpy(buffer,password);//over flowed here! 9 return authenticated; 10 } 11 void main(void) 12 { 13 int valid_flag=0; 14 char password[1024]; 15 FILE * fp; 16 if(!(fp=fopen("password.txt","rw+"))) 17 { 18 exit(0); 19 } 20 fscanf(fp,"%s",password); 21 valid_flag = verify_password(password); 22 if(valid_flag) 23 { 24 printf("incorrect password! "); 25 } 26 else 27 { 28 printf("You have passed the verification! "); 29 } 30 fclose(fp); 31 }
编译成debug版本后,用ollydbg打开,
由图可知通过验证的程序分支的指令地址是0x00401122 如果把返回地址覆盖成这个地址。则程序将直接跳转到验证通过分支。
buffer[0~3]
buffer[4~7]
authenticated
前栈帧EBP
返回地址
在password.txt中,将4321作为一个输入单元,buffer[8]需要2个单元,第三个单元将authenticated覆盖,第四个将EBP覆盖,第五个单元将返回地址覆盖。
用十六进制编辑器UltraEdit将第五个修改为0x00401122即可实现跳转。
代码植入:
将以上程序稍加修改:
1 #include <stdio.h> 2 #include <windows.h> 3 #define PASSWORD "1234567" 4 int verify_password(char *password) 5 { 6 int authenticated; 7 char buffer[44]; 8 authenticated = strcmp(password, PASSWORD); // = ,return 0 9 strcpy(buffer, password); 10 return authenticated; 11 } 12 void main(void) 13 { 14 int valid_flag = 0; 15 char password[1024]; 16 FILE *fp; 17 LoadLibrary("user32.dll"); //for messagebox 18 if(!(fp = fopen("password.txt","rw+"))) 19 { 20 exit(0); 21 } 22 fscanf(fp,"%s",password); 23 valid_flag = verify_password(password); 24 if(valid_flag) 25 printf("incorrect password ! "); 26 else 27 printf("You have passed the verification ! "); 28 fclose(fp); 29 getchar(); 30 31 }
将在password.txt植入用来调用Win API函数MessageBoxA的二进制机器码。
buffer[44]需要11个4321单元....第14个将返回地址覆盖。
先在password.txt写入44个字符,则第45个隐藏的截断符null将冲掉authenticated低字节中的1,从而通过验证,此时运行程序可通过。