Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Не работает декремент и xor


Автор: StillPhelix 27.1.2016, 19:46
Не работает декремент и xor. Коппилируется нормально. Не ребочие строки откоментированны. Исходник ниже. 
Код

#include <Windows.h>
#include <cstdlib>
#include <stdio.h>
#include <time.h>
#include <iso646.h>

using std::srand;
using std::rand;

int main()
{
    printf("CrackMe 09 \n");
    PHKEY hKey;
    DWORD res;
    DWORD TYPE;        
    DWORD Count1;
    DWORD Count2;

    if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res)!=ERROR_SUCCESS)
        return 0;
    if(res==REG_CREATED_NEW_KEY)
    {
        srand((unsigned)time(0));
        Count1=(unsigned)rand();
        Count2=0x100^Count1;
        RegSetValueEx(*hKey, "Count1", 0, REG_DWORD, (CONST BYTE *) &Count1, 4);
        RegSetValueEx(*hKey, "Count2", 0, REG_DWORD, (CONST BYTE *) &Count2, 4);
        printf("Base count have saved! \n");
    } 
    else
    {
        res = 4;
        RegQueryValueEx(*hKey, "Count1", 0, &TYPE, (LPBYTE)&Count1, &res);
        RegQueryValueEx(*hKey, "Count1", 0, &TYPE, (LPBYTE)&Count2, &res);

        Count2 = Count2^Count1;//тут не работает
        Count2--;//тут не работает
        printf("Count  %x \n",Count2);
        if (!Count2) return 0;

        srand((unsigned)time(0));
        Count1 = (unsigned)rand();
        Count2 = Count2^Count1;

        RegSetValueEx(*hKey, "Count1", 0, REG_DWORD, (CONST BYTE *) &Count1, 4);
        RegSetValueEx(*hKey, "Count2", 0, REG_DWORD, (CONST BYTE *) &Count2, 4);
    }
    RegCloseKey(*hKey);
    return 0;
}

Автор: StillPhelix 27.1.2016, 20:39
Код

else
    {
        res = 4;
        RegQueryValueEx(*hKey, "Count1", 0, &TYPE, (LPBYTE)&Count1, &res);
        RegQueryValueEx(*hKey, "Count1", 0, &TYPE, (LPBYTE)&Count2, &res);//Count1 исправить на Count2


Автор: feodorv 27.1.2016, 20:47
Это как так? Память под указатель не выделена, hKey указывает неизвестно куда...
Цитата(StillPhelix @  27.1.2016,  19:46 Найти цитируемый пост)
    PHKEY hKey;
    ...
    if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res)!=ERROR_SUCCESS)
        return 0;


Добавлено через 1 минуту и 52 секунды
Должно быть:
Код
HKEY hKey = NULL;
...
if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, &res)!=ERROR_SUCCESS)
        return 0;
Соответственно, никаких *hKey, просто hKey.

Автор: StillPhelix 28.1.2016, 01:14
Цитата(feodorv @  27.1.2016,  20:47 Найти цитируемый пост)
Это как так? Память под указатель не выделена, hKey указывает неизвестно куда...

прямая цитата из MSDN:
PHKEY
 Pointer to an HKEY. 
This type is declared in WinDef.h as follows:
typedef HANDLE *PHANDLE;

Цитата(feodorv @  27.1.2016,  20:47 Найти цитируемый пост)
Соответственно, никаких *hKey, просто hKey. 

Нет. Прямая цитата из MSDN:
inline LSTATUS CAtlTransactionManager::RegCreateKeyEx(
     HKEY hKey,
     LPCTSTR lpSubKey,
     DWORD dwReserved,
     LPTSTR lpClass,
     DWORD dwOptions,
     REGSAM samDesired,
     CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes,
     PHKEY phkResult,
     LPDWORD lpdwDisposition
  );

Проблема уже решена; смотри мой второй пост. Компилятор - visual studio 2010. Это чистый C++. Ваши правки подойдут только для MFC C++ и в этом случае не канают.


Автор: feodorv 28.1.2016, 03:59
Цитата(StillPhelix @  28.1.2016,  01:14 Найти цитируемый пост)
Проблема уже решена

Это я понял.


Цитата(StillPhelix @  28.1.2016,  01:14 Найти цитируемый пост)
Ваши правки подойдут только для MFC C++ и в этом случае не канают.

Это глупость.


Цитата(StillPhelix @  28.1.2016,  01:14 Найти цитируемый пост)
Нет.

Дело, конечно, Ваше, но когда программа рухнет, не жалуйтесь.


PS Вы бы хоть https://msdn.microsoft.com/en-us/library/windows/desktop/aa446595%28v=vs.85%29.aspx посмотрели, что ли.
Цитата
    HKEY hkSub = NULL;
    ...
lRes = RegCreateKeyEx(HKEY_CURRENT_USER, _T("mykey"), 0, _T(""), 0, 
            KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); 

Вызов RegCreateKeyEx заносит результат по адресу phkResult, то есть по этому адресу обязана располагаться доступная память. https://msdn.microsoft.com/en-us/library/windows/desktop/ms724844%28v=vs.85%29.aspx:
Цитата
A pointer to a variable that receives a handle to the opened or created key.
Указатель у Вас есть, но переменной, на которую он указывает, у Вас нет. Почему для lpdwDisposition вы пишете:
Цитата(StillPhelix @  27.1.2016,  19:46 Найти цитируемый пост)
    DWORD res;
    if (RegCreateKeyEx( ..., &res)!=ERROR_SUCCESS)
а для hKey так не делаете?

Автор: StillPhelix 28.1.2016, 12:04
Цитата(feodorv @  28.1.2016,  03:59 Найти цитируемый пост)
Это глупость.

MFC C++ не вызавает API. Вместо этого она обращается к библиотеке MFC, а та в свою очередь вызывает этот API.  Чистый C++ вызывает API на прямую. Если не верите, то дизассемблируйте две программы, с соответствующими вызовами (на С++ и MFC C++). Все проекты MFC в 2 раза больше по размеру, чем проекты С++. И в visual studio они создаються разными путями. 

Цитата(feodorv @  28.1.2016,  03:59 Найти цитируемый пост)
а для hKey так не делаете?

Переменная, содержащая адрес (hKey) и сам адрес - это две разные вещи. Поэтому, *hKey даст функции значение самой переменной, адрес которой храниться в hKey. Что и нужно данной API. Такой её прототип. Если вас интересует как работать с указателями, то прочитайте об этом, например в этой книге : Харви М. Дейтел, Пол Дж. Дейтел Как программировать на C++ (2008).
Вобщем, &res - это адрес. А hKey, переменная, содержащая адрес.
Поэтому программа не рухнет. С точки зрения С++ и компилятора С++ она написана правильно.

Автор: baldman88 28.1.2016, 14:53
Раз уж Вы так рьяно рассказываете про С++ и советуете читать книги (при этом не самые удачные, ИМХО), то feodorv Вас совершенно правильно ткнул носом в тот факт, что указатель hKey у Вас есть, но вот на что он указывает никому не известно. По стандарту С++ указатели не инициализируются значениями по умолчанию. Таким образом, в один "прекрасный" момент, ваш hKey будет указывать на какой-нибудь участок памяти, который, при записи в него из Вашей программы, сможет вызвать серьезную ошибку в работе ОС. Так что прежде чем грубить, попытайтесь понять, что до Вас хотят донести  smile 

Автор: xvr 28.1.2016, 14:58
2 ТС - очень рекомендуется почитать буквари (можно те, что сами тут и упоминули) прежде чем нести ахинею прикрываясь красивыми словами про MFC/API/C++/прототипы

Автор: StillPhelix 28.1.2016, 16:35
baldman88, 
xvr,
Код

 if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res)!=ERROR_SUCCESS)
 
В этой строке инициализируется дескриптор. smile  smile  smile 

Автор: xvr 28.1.2016, 18:00
Цитата(StillPhelix @ 28.1.2016,  16:35)
Код

 if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res)!=ERROR_SUCCESS)
 
В этой строке инициализируется дескриптор. smile  smile  smile

В этой строке вызов RegCreateKeyEx запишет по указателю hKey ваш дескриптор. Так как этот указатель никто не инициализировал, то и попадет он неизвестно куда. Вам повезло, что там оказалась память и она ни с кем не пересеклась.

Напишите в строке 13 ( PHKEY hKey;) так -
Код

    PHKEY hKey = NULL;
и вы сами все наглядно увидите (если уж чужим словам не верите  smile  )

Автор: StillPhelix 28.1.2016, 19:36
Цитата(xvr @  28.1.2016,  18:00 Найти цитируемый пост)
и вы сами все наглядно увидите (если уж чужим словам не верите  smile  )

Код

PHKEY hKey

это значит, что компилятор выделяет переменной hKey память и адрес.
А код
Код

 if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res)!=ERROR_SUCCESS)

её и так инициализирует. Адрес-то этой переменной функции известен. Памать под переменную выделена. Поэтому обнулять эту переменную смысла никакого нет. Это же не счётчик. 
Современный оптимизирующий копилятор из кода
Код

PHKEY hKey = NULL

 = NULL скорее всего выбросит.
Я эту программу прогонял не только через отладчик (visual studio и winDbg), но и дизассемблер. Код полностью работоспособен. Можете проверить сами.

Автор: baldman88 28.1.2016, 19:53
Я только сейчас понял, что эта функция делает. Видимо внутри она делает что-то вроде:
Код

hKey = new HKEY(...);

Мда. Такое уродливое API еще поискать нужно. Надеюсь никогда не доведется с ним иметь дело.

Автор: StillPhelix 28.1.2016, 21:05
Если коротко, то в SDK от Microsoft, сказано следующее. RegCreateKeyEx передаёт адрес дескриптора созданного ключа в переменную, адрес которой храниться в указателе типа PHKEY ( это hKey). А PHKEY, в свою очередь, указывает на HKEY. RegQueryValueEx, RegSetValueEx и RegSetValueEx требуют значение дескриптора. Сам дескриптор - показывает на нужный объект. Для этого указатель hKey нужно разыменовать. Поэтому пишем: *hKey.

Автор: feodorv 28.1.2016, 22:13
Цитата(StillPhelix @  28.1.2016,  21:05 Найти цитируемый пост)
Если коротко, то в SDK от Microsoft, сказано следующее. RegCreateKeyEx передаёт адрес дескриптора созданного ключа в переменную, адрес которой храниться в указателе типа PHKEY ( это hKey). А PHKEY, в свою очередь, указывает на HKEY. RegQueryValueEx, RegSetValueEx и RegSetValueEx требуют значение дескриптора. Сам дескриптор - показывает на нужный объект. Для этого указатель hKey нужно разыменовать. Поэтому пишем: *hKey. 

В логике Вам не окажешь. Осталось только понять, где именно в коде
Цитата(StillPhelix @  27.1.2016,  19:46 Найти цитируемый пост)
    PHKEY hKey;
    ...
    if (RegCreateKeyEx( ..., hKey, &res)!=ERROR_SUCCESS) return 0;
Вы передаёте в функцию RegCreateKeyEx адрес переменной, в которую будет помещён дескриптор (не адрес дескриптора, конечно) созданного или открытого ключа. Адрес Вы передаёте, не спорю, но адрес чего???


Цитата(StillPhelix @  28.1.2016,  19:36 Найти цитируемый пост)
PHKEY hKey

это значит, что компилятор выделяет переменной hKey память и адрес.
Это значит, что определяется переменная типа "указатель на HKEY", и... всё. Более ничего. Переменная даже не инициализируется. Компилятор автоматом создавать память, на которую указывает hKey, не будет. Разименовывать такой указатель категорически нельзя.


Цитата(StillPhelix @  28.1.2016,  19:36 Найти цитируемый пост)
А код
    
 if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\crack09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res)!=ERROR_SUCCESS)

её и так инициализирует. Адрес-то этой переменной функции известен.
Данный код никоим образом не может проинициализировать переменную hKey, то есть присвоить ей какой-либо адрес типа PHKEY. Но может по адресу, который хранится в hKey, записать какое-либо значение типа HKEY (что не есть инициализация hKey). Поскольку адрес, хранящийся в переменной hKey, мусорный (hKey-то не инициализирована), то и запись возвращаемого функцией RegCreateKeyEx значения типа HKEY произойдёт по мусорному адресу. И адрес какой именно переменной известен функции RegCreateKeyEx? 


Цитата(StillPhelix @  28.1.2016,  19:36 Найти цитируемый пост)
Современный оптимизирующий копилятор

Современный компилятор на подобные конструкции выдаёт предупреждение об использовании переменной hKey без инициализации. У Вас такое предупреждение есть?

Добавлено через 2 минуты и 9 секунд
Цитата(baldman88 @  28.1.2016,  19:53 Найти цитируемый пост)
Такое уродливое API еще поискать нужно.

Зря Вы так. Тогда и fopen тоже уродлив. Что же не уродливо?

Автор: baldman88 29.1.2016, 00:16
Цитата(feodorv @ 28.1.2016,  22:13)
Цитата(baldman88 @  28.1.2016,  19:53 Найти цитируемый пост)
Такое уродливое API еще поискать нужно.

Зря Вы так. Тогда и fopen тоже уродлив. Что же не уродливо?

Про fopen не соглашусь, там все интуитивно понятно. Передаем имя файла и режим в котором хотим открыть файл. В случае успеха получаем адрес, а в случае неудачи -- NULL. Здесь же 100500 параметров, да еще и непонятно что передавать. То ли нужно передать указатель на уже выделенную память, то ли просто указатель, в который будет занесен адрес памяти, которая будет выделена в функции.

Автор: volatile 29.1.2016, 01:08
Цитата(baldman88 @ 28.1.2016,  19:53)
Я только сейчас понял, что эта функция делает. Видимо внутри она делает что-то вроде:
Код

hKey = new HKEY(...);

Мда. Такое уродливое API еще поискать нужно. 

маразм крепчал smile
если это так, то как ваша программа получит этот указатель-то ???
там что, по вашему, ссылка на указатель в аргументах ???

господа baldman88, StillPhelix, вам срочно учить что такое указатель, что такое функция, как передаются и возвращаются параметры функции, а уж потом пытаться лезть в API, и высказывать о ней какие-то критические замечания.

Автор: feodorv 29.1.2016, 03:38
Цитата(baldman88 @  29.1.2016,  00:16 Найти цитируемый пост)
Про fopen не соглашусь, там все интуитивно понятно. Передаем имя файла и режим в котором хотим открыть файл. В случае успеха получаем адрес, а в случае неудачи -- NULL.
fopen возвращает два значения - поток и код ошибки (если она произошла), просто код ошибки записывается в глобальную переменную errno. RegCreateKeyEx возвращает аж три значения - код ошибки, дескриптор ключа и контрольное значение. Разработчики API по каким-то причинам решили не возвращать код ошибки через глобальную переменную, а возвращать его напрямую из функции. Соответственно, для двух других возвращаемых значений требуются указатели, через которые эти значения и возвращаются. Всё справедливо.


Цитата(baldman88 @  29.1.2016,  00:16 Найти цитируемый пост)
То ли нужно передать указатель на уже выделенную память, то ли просто указатель, в который будет занесен адрес памяти, которая будет выделена в функции. 

И Вы туда же. Вызов сишной функции (то есть без привлечения си-плюс-плюсных ссылок) не способен изменить значение передаваемого ей аргумента, если Вы не передавали ей заодно и его адрес. Поэтому hKey каким был до вызова RegCreateKeyEx, таким и остался после. Мусорным, неинициализированным. Но чтобы по адресу, на который указывает hKey, можно было хоть что-то занести, hKey должен указывать на доступную память. Это можно сделать так:
Код
HKEY key;
PHKEY hKey = &key;
Это можно сделать иначе:
Код
HKEY hKey[1];
Но вот так:
Код
PHKEY hKey;
этого сделать не удастся. Но всё же, самый простой и элегантной способ - это объявить переменную типа HKEY, а в функцию передать её адрес через операцию взятия адреса &. Тогда и по переданному в RegCreateKeyEx адресу будет находится доступная память, а в дальнейших вызовах не нужно будет каждый раз делать операцию разыменовывания *, от которой в приведённом ТС коде рябит в глазах.

Автор: baldman88 29.1.2016, 09:04
Цитата(baldman88 @ 28.1.2016,  19:53)
Я только сейчас понял, что эта функция делает. Видимо внутри она делает что-то вроде:
Код

hKey = new HKEY(...);

Посыпаю голову пеплом. Посмотрел объявление этой функции и увидел, что параметр передается не по ссылке.

Автор: xvr 29.1.2016, 14:38
Цитата(StillPhelix @  28.1.2016,  19:36 Найти цитируемый пост)
Можете проверить сами. 

Ну раз уж вы словам не верите, то проверил. Вот ваш код, обрезанный до минимума:
Код

#include <Windows.h>

int main()
{
    PHKEY hKey = (PHKEY)1;
    DWORD res;
    RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\test09", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, hKey, &res);
}
В hKey занесен заранее невалидный указатель (просто NULL не достаточно - RegCreateKeyEx в этом случае просто не записывает никуда результат). По вашей логике в hKey до вызова RegCreateKeyEx может быть что угодно, так?

Вот результат запуска -

Цитата

Unhandled exception at 0x751C847A (kernel32.dll) in ConsoleApplication2.exe: 0xC0000005: Access violation writing location 0x00000001.


Как вы это объясните, великий теоретик вы наш?

Автор: StillPhelix 13.2.2016, 19:59
feodorv, ответы на все ваши вопросы, в библиотеке MSDN или Microsoft Visual Studio Documentation. В частности, ссылка для RegCreateKeyEx в MSDN : https://msdn.microsoft.com/en-us/library/windows/desktop/ms724844%28v=vs.85%29.aspx. По всем остальные вопросы - тудаже. В конце каждой темы есть ссылка на MSDN.

Программа в Microsoft Visual Studio компилируется и работает нормально. Правки, небходимые для нормальной работы во втором посту сверху.

Автор: feodorv 14.2.2016, 05:29
Цитата(StillPhelix @  13.2.2016,  19:59 Найти цитируемый пост)
feodorv, ответы на все ваши вопросы, в библиотеке MSDN

При чем здесь MSDN? Отправлять в функцию неинициализированный указатель - это выстрел в ногу. Сейчас Вам повезло, а потом не повезёт. И я уже писал, что это дело Ваше, раз Ваше упрямство превышает все разумные пределы.
Код

typedef void * HKEY;
typedef HKEY * PHKEY;

void f( PHKEY p )
{
  *p = 0;
}

int main( void )
{
  PHKEY p;
  f( p );
  return 0;
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)