2016-09-13 5 views
5

Я написал простую программу на языке C, цель которой состоит в том, чтобы ученики использовали OllyDbg для ее реверсирования и исправления, чтобы изменить способ ее выполнения. Им нужно только найти 3 и изменить их на 5. Скомпилированный исполняемый файл заполнен сложными для запуска вызовами, которые будут препятствовать попыткам новичков отменить его в Olly. Я хочу сказать компилятору удалить все/большинство из этого.Необходимые параметры компилятора C для создания простого для обратного выполнения для обучения реверсированию

Я использую Visual Studio 2015 Pro, но я не свист VS, я не знаю с чего начать.

+1

Ну, я предполагаю, что эти «вызовы запуска» очень важны для выполнения программы. Может быть, вместо того, чтобы пытаться их вырезать, вы должны подумать о компиляции для более простой цели? Инструментальная цепочка для небольшого встроенного устройства (например, AVR) может генерировать сборку, которая немного проще. Также, если вы используете GCC, вы можете отключить оптимизацию (-O0), что также поможет читаемости сгенерированного кода. –

ответ

3

Пока ваша основная функция не имеет доступа к стандартной библиотеки C и вы используете только вызовы Windows API, вы можете удалить код запуска с-во время выполнения с помощью следующих двух компоновщика переключателей:

/entry:<your_main_function> /nodefaultlib 

В полный пример с использованием приложения простой консоли (который я предположил, что вы используете) и основную функцию «главного», вы можете скомпилировать и скомпоновать код без библиотеки C-выполнения следующим образом:

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

V isual Studio имеет эквивалентные опции, заложенные в ваши диалоги проектов, если вы не хотите вручную запускать инструменты командной строки.

Это должно произвести небольшой, но простой EXE. Когда начнется сеанс отладки, вы должны начать прямо внутри своей основной функции.

ПРИМЕЧАНИЕ. Отсутствие стандартного ввода-вывода может сделать вывод числа (который, как я полагаю, вы делаете) сложнее, поскольку вам может потребоваться написать некоторые процедуры самостоятельно, например, получить длину строки. Однако единственными вызовами API, которые вы должны вывести на консоль, являются функции kernel32 GetStdHandle() и WriteConsole(). Имейте в виду, что есть API wsprintf(), доступный в user32.lib, который я также предлагаю использовать, чтобы сохранить ваши образцы bare-bones, но все же позволить вам создавать строки в стиле c-style. Используйте wsprintf(), чтобы преобразовать ваш номер в строку вывода/строку и использовать WriteConsole для отправки на консоль.

ОБНОВЛЕНИЕ: Ниже приведен пример программы С, которая выводит результаты добавления двух номеров без необходимости использования библиотеки стандартного C и, таким образом, кода запуска CRT. Это хороший обратный инженерный образец, чтобы изменить одно из чисел, чтобы получить другой результат в командной строке.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я согласен с тем, что wsprintf() действительно является небезопасной функцией из-за отсутствия контроля размера буфера и неправильного использования может привести к переполнению буфера. Он используется здесь ТОЛЬКО, потому что он встроен в Win32 API (user32.lib) и является быстрым способом преобразования числа в строку только для этого примера.

Насколько я знаю, единственными функциями форматирования в стиле С, встроенными в окна, являются версии этой функции 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); 
} 
+0

Спасибо @bytepointer, используя функции GetStdHandle() и WriteConsole() из kernel32, а затем используя параметры компилятора/компоновщика, которые вы дали, было именно то, что мне нужно. Произведенный исполняемый файл легко для ученика, чтобы он обратился в Олли. Спасибо также за ** очень ** хороший пример кода, который вы добавили позже. Я отмечаю ваш ответ. – mvwhyatt