c - 需要 C 编译器选项来创建易于逆向的可执行文件来教授逆向

标签 c visual-studio visual-studio-2015 reverse-engineering

我编写了一个简单的 C 程序,目的是让学生使用 OllyDbg 反转它并修补它以改变它的执行方式。他们只需要找到一个 3 并将其更改为 5。编译后的可执行文件充满了难以理解的启动调用,这将阻碍新手在 Olly 中逆向它的努力。我想告诉编译器删除所有/大部分内容。

我正在使用 Visual Studio 2015 Pro,但我不是 VS 高手,我不知道从哪里开始。

最佳答案

只要您的主函数不访问标准 C 库并且您只使用 Windows API 调用,您就可以使用以下两个链接器开关删除 c-runtime 启动代码:

/entry:<your_main_function> /nodefaultlib

在一个使用简单控制台应用程序(我假设您正在使用)和“main”的主要功能的完整示例中,您可以编译和链接您的代码 c-runtime库如下:

cl /c main.c
link /entry:main /nodefaultlib /libpath:<path_to_libs> /subsystem:console main.obj kernel32.lib user32.lib

如果您不想手动运行命令行工具,Visual Studio 在您的项目对话框中隐藏了等效选项。

这应该会生成一个小而简单的 EXE。当您的调试 session 开始时,您应该从您的主函数开始。

注意:缺少标准 IO 可能会使输出数字(我假设您正在做)更加困难,因为您可能需要自己编写一些例程,例如获取字符串长度。然而,您需要输出到控制台的唯一 API 调用是 kernel32 GetStdHandle() 和 WriteConsole() 函数。请记住,在 user32.lib 中有一个 wsprintf() API 可以访问,我还建议使用它来保持示例的基本结构,但仍然允许您构建 c 风格的格式化字符串。使用 wsprintf() 将您的数字转换为输出提示/字符串,并使用 WriteConsole 将其发送到控制台。

更新:下面是一个示例 C 程序,无需标准 C 库和 CRT 启动代码即可输出两个数字相加的结果。这是一个很好的逆向工程示例,用于更改其中一个数字以在命令行上获得不同的结果。

免责声明:我同意 wsprintf() 确实是一个不安全 函数,因为它不检查缓冲区大小,而且如果使用不当会导致缓冲区溢出。此处使用它仅是因为它内置于 Win32 API (user32.lib) 中,并且仅针对此示例是一种将数字转换为字符串的快速方法。

据我所知,Windows 中内置的唯一 C 样式格式化函数是该函数的 ANSI/WIDE 版本。 strsafe.lib 函数似乎依赖于标准库,否则我会使用它们。如果您知道任何不同,请告诉我!因此,如果您不使用标准 C 库函数,我建议您编写自己的数字到字符串转换函数或使用其他人的函数。

#include <Windows.h>

//quick-and-dirty string-length function
DWORD getStringLen(const char* pszStr)
{
    const char* p = pszStr;
    while(*p) ++p;
    return(p - pszStr);
}

//program entry point - note that int return value does propagate back to
//    ExitProcess() despite main() being the program's actual entry point;
//    the ret at the end of this function returns back to the loader, which
//    in turn calls ExitThread() with EAX; the return value can be
//    checked on the comamnd-line via: echo %ERRORLEVEL%
int main(void)
{
    DWORD dwNum1 = 5;
    DWORD dwNum2 = 3;
    DWORD dwResult = dwNum1+dwNum2;

    //build formatted output string
    //
    // NOTE: wsprintfA() is an unsafe function and is only used as an example
    //       DO NOT USE in production code!
    //
    #pragma warning(disable : 4995) //wsprintf is a depreciated function
    char szTemp[100];
    int iRet = wsprintfA(szTemp,"%u + %u = %u\n",dwNum1,dwNum2,dwResult);

    //get console stdandard output handle
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    if (INVALID_HANDLE_VALUE == hConsole)
    {
        iRet = -1;
    }
    else
    {
        //output the string
        WriteConsoleA(hConsole,szTemp,getStringLen(szTemp),&dwNum1,NULL);
    }

    return(iRet);
}

关于c - 需要 C 编译器选项来创建易于逆向的可执行文件来教授逆向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39476614/

相关文章:

c - Xcode 中的段错误,调试器无法帮助我

c# - 有没有办法在 VS 调试器中自定义自定义对象的工具提示?

c# - 构建一个 web 项目破坏了解决方案中第二个的编译版本

c - 什么比长双倍更大?

c - 如果有两个空格,它会算作3个字

asp.net - 如何清除 Windows Vista 上的 Visual Studio 缓存?

c# - 以编程方式生成 Visual Studio 解决方案

c++ - 跨 C++ 模块传递指向成员函数的指针

c++ - Microsoft VS2015 C++ Core Guidelines分析: "no array to pointer decay (bounds.3)" for vtable?

c++ - 正在使用的文件 C/C++