Привет всем. Есть одна карточная игра Canasta. Игра требует регистрации. Методом трассировки в Oly смог найти вытащить ключи генерируемые программой по вводимому имени. Есть листинг "исходника" на асме, но там сам черт ногу сломит. Как только не пытался я найти зависимости, не смог. Там или шифрование или битовые сдвиги. Вот пример Для вводимого имени 0 ключ 104160 00 ключ 119520 000 ключ 130368 Причем при трасировке алгоритм кажется переворачивает числа, т.е. в консоле вначале 061 и 401 потом превращаются в 104160. Вот исходник, как я предполагаю генерации Код (Text): v10; v14[v4++] = v11 + 48; } while ( v3 ); if ( v5 < 0 ) v14[v4++] = 45; *(_BYTE *)a3 = v4; v7 = a3 + 1; v6 = v13; if ( v13 > 255 ) v6 = 255; v12 = __SETO__(v6, v4); v8 = v6 - v4; if ( !((unsigned __int8)(v8 < 0 ^ v12) | v8 == 0) ) { *(_BYTE *)(v7 - 1) += v8; while ( v8 ) { *(_BYTE *)v7++ = 32; --v8; } } do { result = v15[v4]; *(_BYTE *)v7++ = result; --v4; } while ( v4 ); return result; файл программы прикрепляю
В трех соснах заблудился. Код (C++): #include "pch.h" #include <iostream> int main() { unsigned char username[] ={'0','0','0'}; unsigned int table1[]={0x000000D9,0x00000063,0x00000058,0x00000022,0x0000003E,0x00000093,0x000000F0,0x00000008, 0x00000034,0x00000062,0x0000001B,0x000000BF,0x000000D7,0x000000B9,0x0000006F,0x0000004A, 0x0000005A,0x000000B2,0x00000084,0x00000024}; unsigned int key=0; do { for(int i=0;i<sizeof(username);i++)key+=username[i]*(i+1)*table1[i]; key%=1000000; } while(key<100000); printf("key=%d\r\n",key); } Код (Text): key=130368
Если не сложно, можно подробнее. Не из размещенного же мной кода ты вытащил. Да еще так быстро. Каким софтом пользоваться? Игра написана на Delphi. Прогнал через DeDe но не сильно помогло
Ollydbg, EmEditor, Fasm. Рипнул, выкинул все лишнее. Все эти вызовы - обработка ошибок при куче бесполезных (кроме длины юзернейма, 20 символов) проверок. Остались кропали:
f13nd, класс , спасибо. А массив как обнаружить? unsigned int table1[]={0x000000D9,0x00000063,0x00000058,0x00000022,0x0000003E,0x00000093,0x000000F0,0x00000008, 0x00000034,0x00000062,0x0000001B,0x000000BF,0x000000D7,0x000000B9,0x0000006F,0x0000004A, 0x0000005A,0x000000B2,0x00000084,0x00000024};
В смысле как? По его базе выбирается множитель: Код (ASM): 004C333A IMUL EBP,DWORD PTR DS:[EAX*4+4F61CC]
почему username меняется? а значения из table1 напротив остаются как есть username=80 tab=34 key=65184 username=160 tab=34 key=97776 username=240 tab=34 key=130368 username=64 key=130368
Значения массива - множители, для каждой позиции символа юзернейма. Первый всегда *=1*0xD9 и складывается в общую сумму, второй всегда *=2*0x63 и складывается в общую сумму и т.д. Ключ не может быть меньше 6 символов: в нем намеренно числа 7+ разрядов преобразуются в остаток от деления на 1000000 и если получается меньше 6 разрядов, делается еще одна итерация. Откуда эти выкладки? Код (Text): '80' 108280 '160' 101991 '240' 101454 '64' 110070
наверное это особенности языка с++, уже все поперепробывал. не сходится при первых значениях table1=217 username=48 строка будет выглядить так key=key+username*(i+1)*table1; ключ= ключ+48*(0+1)*217 будет 10416 -------------------------------------------------- что значит *= , как массив символов может быть множителем? знаю что нубские вопросы достали, правда хочу разобраться ((
'a*=b' означает 'a=a*b' Код (Text): username='123' //{0x31,0x32,0x33} key=0 key = 0 + 0x31*1+0xD9 + 0x32*2+0x63 + 0x33*3+0x58 = 0x2989 + 0x26AC + 0x3498 = 0x84CD key = key % 0xF4240 = 0x84CD //0x84CD меньше 0x186A0, еще итерация key = 0x84CD + 0x31*1+0xD9 + 0x32*2+0x63 + 0x33*3+0x58 = 0x84CD + 0x84CD = 0x1099A key = key % 0xF4240 = 0x1099A //0x1099A меньше 0x186A0, еще итерация key = 0x1099A + 0x31*1+0xD9 + 0x32*2+0x63 + 0x33*3+0x58 = 0x1099A + 0x84CD = 0x18E67 key = key % 0xF4240 = 0x18E67 //0x18E67 больше 0x186A0 key = 0x18E67 = 101991
Вот опять, я Вас не допонимаю либо потому что Вы в уме часть додумываете, либо особенности языка с++ key = 0 + 0x31*1+(тут)0xD9 + 0x32*2+(тут)0x63 + 0x33*3(тут)+0x58 = 0x2989 + 0x26AC + 0x3498 = 0x84CD разве не знак умножить? иначе не получается 0x84CD Как мы можем получать тоже значение над которым производим действия деления? key = key % 0xF4240 = 0x84CD ключ = ключ / 0xF4240 = ключ ????
Да, там знак "умножить" должен быть. Оператор % в си это остаток от деления. Если хотя бы на базовом уровне ассемблер знаешь (иначе не нашел бы в ольге этот алгоритм), должен знать как idiv работает и что оказывается в edx после него. Третьи сутки разжовываю одну строчку алгоритма.
если честно ассемблер не очень знаю, так ковырял, смотрел адреса процедур, ставил брекпоинты и интуитивно добрался до алгоритма генерации ключа так на асме писал, и сейчас напишу программу простенькую, но когда дело доходит до исследования программ теряюсь в регистрах. что посоветуете для этого. Нужно именно понимание как у Вас. Вот вы увидили строчку IMUL EBP,DWORD PTR DS:[EAX*4+4F61CC] и сразу поняли что массив. Как такого уровня достич? особенно когда не явно указан регистр а смещение вообще в ступор вводит (((( p.s. извините что отошел от темы, пытался личное сообщение отправить , но Вам нельзя почему-то их отправлять
А разве не очевидно, что это выборка значения из памяти по индексу, скалируемому на 4 (размер двойного слова)? Почему регистр указан неявно? Это общий для всего набора инструкций х86 способ адресации: комбинация из sib-байта и оффсета. Эти квадратные скобки быстро примелькаются, будешь видеть. В регистрах общего назначения х86 сложно потеряться: их меньше, чем пальцев на руках Как достичь? Лет 15 заниматься реверсом. Впервые слышу, чтобы кто-то интуитивно разобрался в лицензионной защите программы, не зная ни асма, ни устройства РЕ-файлов. Со мной примерно так же и было. Практикуйся, будет получаться. Многим книжки и гайды в этом помогают (а немногим даже это не в коня корм), можешь что-нибудь из такого поискать.