• C语言/C++内嵌汇编代码实例:文件加密

    现在查看的简短程序实现如下操作:读取一个文件,对其进行加密,再将其输出到另一个文件。函数 TranslateBuffer 用一个 __asm 块定义语句,在一个字符数组内进行循环,并把每个字符与预定义值进行 XOR 运算。

    内嵌语言可以使用函数形参、局部变量和代码标号。由于本例是由 Microsoft Visual C++ 编译的 Win32 控制台应用,因此其无符号整数类型为 32 位:

    void TranslateBuffer(char * buf,
        unsigned count, unsigned char eChar)
    {
        __asm {
            mov esi, buf
            mov ecx, count
            mov al, eChar
        L1:
            xor [esi],al
            inc esi
            loop L1
        }    // asm
    }

    C++ 模块

    C++ 启动程序从命令行读取输入和输出文件名。在循环内调用 TranslateBuffer 从文件读取数据块,加密,再将转换后的缓冲区写入新文件:

    // ENCODE.CPP    复制并加密文件。
    #include <iostream>
    #include <fstream>
    #include "translat.h"
    
    using namespace std;
    
    int main( int argcount, char * args[] )
    { 
        // 从命令行读取输入和输出文件
        if( argcount < 3 ) {
            cout << "Usage: encode infile outfile" << endl;
            return -1;
        }
    
        const int BUFSIZE = 2000;
        char buffer[BUFSIZE];
        unsigned int count;            // 字符计算
     
        unsigned char encryptCode;
        cout << "Encryption code [0-255]? ";
        cin >> encryptCode;
    
        ifstream infile( args[1], ios::binary );
        ofstream outfile( args[2], ios::binary );
    
        cout << "Reading " << args[1] << " and creating "
            << args[2] << endl;
    
        while (!infile.eof() )
        {
            infile.read(buffer, BUFSIZE );
            count = infile.gcount();
            TranslateBuffer(buffer, count, encryptCode);
            outfile.write(buffer, count);
        }
        return 0;
    }

    用命令提示符运行该程序,并传递输入和输岀文件名是最容易的。比如,下面的命令行读取 infile.txt,生成 encoded.txt:

    encode infile.txt encoded.txt

    头文件

    头文件 translat.h 包含了 TranslateBuffer 的一个函数原型:

    void TranslateBuffer(char * buf, unsigned count, unsigned char eChar);

    过程调用的开销

    如果在调试器调试程序时查看 Disassembly 窗口,那么,看到函数调用和返回究竟有多少开销是很有趣的。下面的语句将三个实参送入堆栈,并调用 TranslateBuffer。在 Visual C++ 的 Disassembly 窗口,激活 Show Source Code 和 Show Symbol Names 选项:

    ; TranslateBuffer(buffer, count, encryptCode)
    mov al,byte ptr [encryptCode]
    push eax
    mov ecx,dword ptr [count]
    push ecx
    lea edx,[buffer]
    push edx
    call TranslateBuffer (4159BFh)
    add esp, 0Ch

    下面的代码对 TranslateBuffer 进行反汇编。编译器自动插入了一些语句用于设置 EBP,以及保存标准寄存器集合,集合内的寄存器不论是否真的会被过程修改,总是被保存。

    push ebp
    mov ebp, esp
    sub esp,40h
    push ebx
    push esi
    push edi
    ;内嵌代码从这里开始。
    mov esi,dword ptr [buf]
    mov ecx,dword ptr [count]
    mov al,byte ptr [eChar]
    L1:
        xor byte ptr [esi],al
        inc esi
        loop L1 (41D762h)
    ;内嵌代码结束。
    pop edi
    pop esi
    pop ebx
    mov esp,ebp
    pop ebp
    ret

    若关闭了调试器 Disassembly 窗口的 Display Symbol Names 选项,则将参数送入寄存器的三条语句如下:

    mov esi,dword ptr [ebp+8]
    mov ecx,dword ptr [ebp+0Ch]
    mov al,byte ptr [ebp+10h]

    编译器按要求生成 Debug 目标代码,这是非优化代码,适合于交互式调试。如果选择 Release 目标代码,那么编译器生成的代码就会更加有效(但易读性更差)。

    忽略过程调用

    本节前面给出的 TranslateBuffer 中有 6 条内嵌指令,其执行总共需要 8 条指令。

    如果函数被调用几千次,那么其执行时间就比较可观了。为了消除这种开销,把内嵌代码插入调用 TranslateBuffer 的循环,得到更为有效的程序:

    while (!infile.eof() )
      {
        infile.read(buffer, BUFSIZE );
        count = infile.gcount();
    
        __asm {
           lea esi,buffer
           mov ecx,count
           mov al, encryptCode
        L1:
           xor [esi],al
           inc  esi
           Loop L1
       } // asm
       
        outfile.write(buffer, count);
      }

更多...

加载中...