Fork me on GitHub

集训第五天:从汇编语言到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

本站访客数: