集训第五天:从汇编语言到C语言
初次见面的学长今天给我们简单讲解了“从汇编语言到C语言”,并布置了一些例题。
if
if就是通过简单的一个CMP判断后JMP来实现
#include<stdio.h>
int main(){
int a = 1;
if(a > 0)
printf("greater");
return 0;
}
汇编代码:
0x10ddcff50 <+0>: pushq %rbp
0x10ddcff51 <+1>: movq %rsp, %rbp
0x10ddcff54 <+4>: subq $0x10, %rsp
0x10ddcff58 <+8>: movl $0x0, -0x4(%rbp)
0x10ddcff5f <+15>: movl $0x1, -0x8(%rbp)
->0x10ddcff66 <+22>: cmpl $0x0, -0x8(%rbp)
0x10ddcff6a <+26>: jle 0x10ddcff81 ; <+49> at main.cpp
0x10ddcff70 <+32>: leaq 0x33(%rip), %rdi ; "greater"
0x10ddcff77 <+39>: movb $0x0, %al
0x10ddcff79 <+41>: callq 0x10ddcff8a ; symbol stub for: printf
0x10ddcff7e <+46>: movl %eax, -0xc(%rbp)
0x10ddcff81 <+49>: xorl %eax, %eax
0x10ddcff83 <+51>: addq $0x10, %rsp
0x10ddcff87 <+55>: popq %rbp
0x10ddcff88 <+56>: retq
if else
相比if多了一个条件,需要加一个JMP
#include<stdio.h>
int main()
{
int a = 1;
if(a > 0)
printf("greater");
else
printf("smaller");
return 0;
}
汇编代码:
0x106f1ef30 <+0>: pushq %rbp
0x106f1ef31 <+1>: movq %rsp, %rbp
0x106f1ef34 <+4>: subq $0x10, %rsp
0x106f1ef38 <+8>: movl $0x0, -0x4(%rbp)
0x106f1ef3f <+15>: movl $0x1, -0x8(%rbp)
-> 0x106f1ef46 <+22>: cmpl $0x0, -0x8(%rbp)
0x106f1ef4a <+26>: jle 0x106f1ef66 ; <+54> at main.cpp
0x106f1ef50 <+32>: leaq 0x4b(%rip), %rdi ; "greater"
0x106f1ef57 <+39>: movb $0x0, %al
0x106f1ef59 <+41>: callq 0x106f1ef80 ; symbol stub for: printf
0x106f1ef5e <+46>: movl %eax, -0xc(%rbp)
0x106f1ef61 <+49>: jmp 0x106f1ef77 ; <+71> at main.cpp
0x106f1ef66 <+54>: leaq 0x3d(%rip), %rdi ; "smaller"
0x106f1ef6d <+61>: movb $0x0, %al
0x106f1ef6f <+63>: callq 0x106f1ef80 ; symbol stub for: printf
0x106f1ef74 <+68>: movl %eax, -0x10(%rbp)
0x106f1ef77 <+71>: xorl %eax, %eax
0x106f1ef79 <+73>: addq $0x10, %rsp
0x106f1ef7d <+77>: popq %rbp
0x106f1ef7e <+78>: retq
do while
do while在每次循环结束时会进行一次CMP,然后判断后再JMP或者继续执行
#include<stdio.h>
int main()
{
int a = 1;
do
{
a++;
}while(a < 10);
return 0;
}
汇编代码:
0x106d3df80 <+0>: pushq %rbp
0x106d3df81 <+1>: movq %rsp, %rbp
0x106d3df84 <+4>: movl $0x0, -0x4(%rbp)
0x106d3df8b <+11>: movl $0x1, -0x8(%rbp)
-> 0x106d3df92 <+18>: movl -0x8(%rbp), %eax
0x106d3df95 <+21>: addl $0x1, %eax
0x106d3df98 <+24>: movl %eax, -0x8(%rbp)
0x106d3df9b <+27>: cmpl $0xa, -0x8(%rbp)
0x106d3df9f <+31>: jl 0x106d3df92 ; <+18> at main.cpp:240
0x106d3dfa5 <+37>: xorl %eax, %eax
0x106d3dfa7 <+39>: popq %rbp
0x106d3dfa8 <+40>: retq
switch case
switch case需要对每个条件逐个判断,满足条件时,JMP出循环
#include <stdio.h>
#include
int main()
{
int a = rand();
switch(a)
{
case 1:
printf("1");
break;
case 2:
printf("2");
break;
default:
printf("No");
break;
}
return 0;
}
输入1后的汇编代码:
0x107c94ef0 <+0>: pushq %rbp
0x107c94ef1 <+1>: movq %rsp, %rbp
0x107c94ef4 <+4>: subq $0x20, %rsp
0x107c94ef8 <+8>: movl $0x0, -0x4(%rbp)
0x107c94eff <+15>: callq 0x107c94f80 ; symbol stub for: rand
0x107c94f04 <+20>: movl %eax, -0x8(%rbp)
-> 0x107c94f07 <+23>: movl -0x8(%rbp), %eax
0x107c94f0a <+26>: movl %eax, %ecx
0x107c94f0c <+28>: subl $0x1, %ecx
0x107c94f0f <+31>: movl %eax, -0xc(%rbp)
0x107c94f12 <+34>: movl %ecx, -0x10(%rbp)
0x107c94f15 <+37>: je 0x107c94f34 ; <+68> at main.cpp
0x107c94f1b <+43>: jmp 0x107c94f20 ; <+48> at main.cpp
0x107c94f20 <+48>: movl -0xc(%rbp), %eax
0x107c94f23 <+51>: subl $0x2, %eax
0x107c94f26 <+54>: movl %eax, -0x14(%rbp)
0x107c94f29 <+57>: je 0x107c94f4a ; <+90> at main.cpp
0x107c94f2f <+63>: jmp 0x107c94f60 ; <+112> at main.cpp
0x107c94f34 <+68>: leaq 0x71(%rip), %rdi ; "'1'"
0x107c94f3b <+75>: movb $0x0, %al
0x107c94f3d <+77>: callq 0x107c94f7a ; symbol stub for: printf
0x107c94f42 <+82>: movl %eax, -0x18(%rbp)
0x107c94f45 <+85>: jmp 0x107c94f71 ; <+129> at main.cpp
0x107c94f4a <+90>: leaq 0x5d(%rip), %rdi ; "'2'"
0x107c94f51 <+97>: movb $0x0, %al
0x107c94f53 <+99>: callq 0x107c94f7a ; symbol stub for: printf
0x107c94f58 <+104>: movl %eax, -0x1c(%rbp)
0x107c94f5b <+107>: jmp 0x107c94f71 ; <+129> at main.cpp
0x107c94f60 <+112>: leaq 0x49(%rip), %rdi ; "No"
0x107c94f67 <+119>: movb $0x0, %al
0x107c94f69 <+121>: callq 0x107c94f7a ; symbol stub for: printf
0x107c94f6e <+126>: movl %eax, -0x20(%rbp)
0x107c94f71 <+129>: xorl %eax, %eax
0x107c94f73 <+131>: addq $0x20, %rsp
0x107c94f77 <+135>: popq %rbp
0x107c94f78 <+136>: retq
homework
在虚拟机里运行OD并打开homework.exe,并找到main函数
阅读并观察汇编程序,然后推测源程序的代码
这里可以看到puts函数输出一段字符串:“please input the flag”,然后有一个scanf函数来接收输入的字符串。
strlen比较字符串长度
关键代码段和strcmp比较字符串
关键代码段处:
MOV [local.5],0x0
JMP short homework.00401452
MOV ECX,[local.5]
MOV EAX,[local.5]
MOV DL,byte ptr ss:[EBP+EAX-0x98]
MOV EAX,[local.5]
XOR EAX,EDX
MOV byte ptr ss:[EBP+ECX-0x98],AL
INC [local.5]
CMP [local.5],0x1A
JLE short homework.00401436
这里的[local.5]可以理解为一个变量,EAX中存放的是变量[local.5]的值,EDX中存放的是输入的字符串中的一个字符。设[local.5]的值为i,每次取出字符串中第i个字符,将该字符与i进行异或,结果存入字符串的第i个。
最后经过操作后等于被加密字符串就会Congratulations
容易知道需要求出解密算法才能获得正确的字符串
因为异或运算可以通过二次运算重新得到
#include <stdio.h>
int main()
{
int a = 1;
printf("%d\n%d\n%d\n", a, a ^ 100, a ^ 100 ^ 100);
return 0;
}
故这里的加密属于一种对称加密方式,只需要将被加密的字符串再加密一次就能的到
#include <stdio.h>
int main()
{
char str[28] = "Tnfb}eu'`fgn{b|d0xa3gz6ryjc";
for(int i = 0; i < 27; i++)
str[i] ^= i;
printf("%s", str);
return 0;
}
拿到flag:
Today`s homework is so easy