1

我用 C++ 写了一个简单的程序:

#include <stdio.h>

const signed char pass[] = "\x70\x61\x73\x73\x77\x6F\x72\x64";

bool __stdcall check_password(const signed char * str)
{
    unsigned int i;
    for(i=0;i<8;++i)
        if(str[i]!=pass[i])
            return false;
    return true;
}

int main(int argc, char * argv[])
{
    signed char buf[20];
    printf("please enter the password: ");
    scanf("%s",buf);
    printf((check_password(buf)) ? "correct!\n" : "incorrect.\nPress any key to exit..\n");
    getchar();
    return 0;
} 


并用visual studio express 2010编译它。
我在OllyDbg中打开了结果,这就是我看到的:

Address   Hex dump            Command                                          Comments
00FF1011  ³.  8B35 A020FF00   MOV ESI,DWORD PTR DS:[<&MSVCR100.printf>]
00FF1017  ³.  68 0021FF00     PUSH OFFSET pass2.00FF2100                       ; ASCII "please enter the password: "
00FF101C  ³.  FFD6            CALL ESI
00FF101E  ³.  8D45 E8         LEA EAX,[LOCAL.6]
00FF1021  ³.  50              PUSH EAX
00FF1022  ³.  68 1C21FF00     PUSH OFFSET pass2.00FF211C                       ; ASCII "%s"
00FF1027  ³.  FF15 A820FF00   CALL DWORD PTR DS:[<&MSVCR100.scanf>]
00FF102D  ³.  83C4 0C         ADD ESP,0C
00FF1030  ³.  33C0            XOR EAX,EAX
00FF1032  ³>  8A4C05 E8       MOV CL,BYTE PTR SS:[EAX+EBP-18]
00FF1036  ³.  3A88 F420FF00   CMP CL,BYTE PTR DS:[EAX+pass2.pass]             ; ASCII "password"
00FF103C  ³. 75 0D           JNE SHORT pass2.00FF104B
00FF103E  ³.  40              INC EAX
00FF103F  ³.  83F8 08         CMP EAX,8
00FF1042  ³. 72 EE           JB SHORT pass2.00FF1032
00FF1044  ³.  B8 2021FF00     MOV EAX,OFFSET pass2.00FF2120                    ; ASCII "correct!\n"
00FF1049  ³. EB 05           JMP SHORT pass2.00FF1050
00FF104B  ³>  B8 2C21FF00     MOV EAX,OFFSET pass2.00FF212C                    ; ASCII "incorrect.\nPress any key to exit..\n"
00FF1050  ³>  50              PUSH EAX
00FF1051  ³.  FFD6            CALL ESI
00FF1053  ³.  83C4 04         ADD ESP,4
00FF1056  ³.  FF15 9C20FF00   CALL DWORD PTR DS:[<&MSVCR100.getchar>]

看起来该函数check_password已被内联,因为我看不到任何 CALL 指令。

所以我的问题是,我怎样才能防止这种情况发生?有没有办法告诉编译器我希望函数出现在可执行文件中?

我问的原因是因为我正在尝试执行 DLL 注入,而我的主要目标是将调用重定向check_password到另一个函数。

4

1 回答 1

5

asm 中没有宏之类的东西(它只是代码的文本替换,发生在代码编译之前)。您所指的是该函数已被内联,通常当编译器决定这样做时,这是一件好事,没有 c++ 广泛的方法可以做到这一点,但您可以做这样的事情

class X {
     __declspec(noinline) int member_func() {
          return 0; 
     }
};

取自这个答案的代码。
这将防止函数被内联。请记住,大多数时候内联是一件好事,因为它消除了函数调用的开销,除了代码膨胀和调试之外,它也没有真正的负面影响。编译器非常聪明,通常会做出关于内联的正确决策。正如您可能已经知道的那样,您可以使用inlinec++ 中的说明符向编译器建议该函数应该被内联。

我最初还认为防止函数内联的更便携的方法是从函数指针调用它,但是这篇文章另有说明。

对于使用gcc查看此答案的人,您可以防止像这样的 void 内联,void __attribute__ ((noinline)) myfunc()这看起来也适用于 clang(我使用的是 Apple clang 4.0 版),因此应该涵盖人们将使用的大多数 c++ 编译器。

于 2013-07-30T23:50:20.617 回答