f13nd, нифига себе ты быстро, я только открыл в Ида семпл. А чем ты пользуешься, сугубо гидрой или в отладчике смотришь? Rel, прикол в том , что семпл палится виндефом как какое-то семейство малвари. Это на тему адекватности аверов.
Я вообще-то еще и работал когда он запостил Как руки дошли. Нет, тупо оллидебаггер, я ж не крякер вообще.
мы вон с поцонами в баню сходили в честь праздничка. а тут уже всё да? ну, вот моё участие - в этом сообщении
f13nd, стряхиваю три слоя абстрактно-виртуализированной пыли с чорной шапки-петушка и передаю её Вам!
Через карты не решается, если каждое условное ветвление инвертировать(^1), это ничего не даёт Код (Text): ; Jcc 41 ; Ip/FlowIp $ 4082F8 $+4 4082FA $+8 408445 $+C 40843B $+10 408440 $+14 408442 $+18 408445 $+1C 408447 $+20 4084AC $+24 4084AE $+28 407ACC $+2C 407AD2 $+30 407AD9 $+34 407ADF $+38 407AF0 $+3C 407B5B $+40 407B65 $+44 407B67 $+48 407B70 $+4C 407B94 $+50 407ACC $+54 407BDF $+58 4084BC $+5C 4084BE $+60 401C02 $+64 401C04 $+68 408706 $+6C 408708 $+70 40870C $+74 408713 $+78 408729 $+7C 40872B $+80 4077B1 $+84 4077B3 $+88 4077CD $+8C 4077CF $+90 407293 $+94 4072A4 $+98 4072A9 $+9C 4072AF $+A0 4072A9 $+A4 4072AB $+A8 40720B $+AC 40720D $+B0 407659 $+B4 40765B $+B8 4076F1 $+BC 4076F3 $+C0 407E97 $+C4 407E99 $+C8 4016C1 $+CC 4016C3 $+D0 409969 $+D4 409936 $+D8 401BC8 $+DC 401BD0 $+E0 401BDA $+E4 401BDC $+E8 401BC8 $+EC 401BCA $+F0 401BCC $+F4 401BE8 $+F8 401BEC $+FC 401BEE $+100 40995F $+104 4099BF $+108 4099CA $+10C 4099A3 $+110 40242A $+114 402451 $+118 4099AE $+11C 4099BE $+120 4099CA $+124 4099CC $+128 4099CE $+12C 4099D0 $+130 4099D4 $+134 4099D6 $+138 4099E5 $+13C 409A28 $+140 4013A3 $+144 40149B Врядле как то автоматикой можно решить, без разбора логики. Аналогично как классический км - вычисление хэш функции от строки, затем его проверка на валидность и ветвление на адрес функции от хэша. Такое было у TrashGen, надо было угадать куда должно передаваться управление..
Это типа cfg или как оно там, тупо последовательность адресов куда передавалось управление. Что ты в этой филькиной грамоте хотел увидеть? Чисто технически можно было бы по многократным примерно равномерным повторениям одних и тех же конкретных иструкций на конкретном месте догадаться, что там хеш считается. Но это как бы слегка мазохизм и действие ради действия.
f13nd, > Это типа cfg или как оно там Последовательность условий не выполненных до ввода. Может не быть условного ветвления, а быть условная выборка - cmov, но такой нет ни одной. Если нет вычисления хэша, то такое работает на большинстве семплов.
А зачем тебе условия выполненные/не выполненные до ввода? Там ведь что с хешем что без самое интересное после ввода происходить должно. ЗЫ: я-то думал, нафига там вся эта свистопляска вокруг z-бита несчастного: Код (Text): $74F1 CMP EDX,EAX $74F3 SETE DL ... $1A19 MOV EBX,EDX ... $1A32 CMP BL,1 ... $1A3D SBB EDI,EDI ... $1A47 AND EDI,00000035 ... $1A59 SUB EDI,1B ... ;eax=просто_адова_помойка ... $1A6A LEA EBX,[EAX+1] $1A6D XOR EDI,EBX ... А оно оказывается метод противодействия визорам, в который я не уперся ни разу.
f13nd, > не выполненные до ввода? Выделяются после ввода, до ввода лог не ведётся. Вот например у тебя 4074F3 setc, если закартировать setc, то после ввода в логе будет одна 407712, тк 4074F3 вызывается до ввода. > метод противодействия визорам Причём тут визоры, трешевая лента. Функция вообще обратима ?
Откуда мне знать? Смысл в том, чтобы знать как можно меньше, выясняется только нужная для решения инфа. Мне в процессе показалось, что это md5, ибо 128 бит там крутятся, но вообще было пофигу.
f13nd, Посмотрел несколько семплов отсюда. Большинство где нет хэширования быстро решается картами, не все подряд, но большая часть. Вот на рандомной выборке взял свежие. Ultimatum CrackMe - выбрал по названию, типо сложный должен быть.. Листаю карту с конца и ищу ветвления, которые идут после сравнения значений, отличных от 0/1. Код (Text): $+248 0040214F <--- $+24C 00402161 $+250 004023A0 $+254 004023A2 $+258 004023C6 $+25C 004023CC $+260 004023D3 $+264 004023DD $+268 004023E3 $+26C 004023E9 $+270 004023E9 $+274 004023EB $+278 004023ED $+27C 004023F3 $+280 00402407 $+284 00402409 $+288 00402410 $+28C 00402412 $+290 0040242C $+294 00402433 $+298 004023E3 $+29C 00402479 $+2A0 004024BE $+2A4 004024C0 $+2A8 00402410 $+2AC 00402424 $+2B0 004048EA $+2B4 004048EC $+2B8 00000000 - на этой инструкции в стеке пасс: Код (Text): 0012FF44 00429968 ASCII "Password: " 0012FF48 00155B10 0012FF4C 00155C38 ASCII "VGhpcyBpcyB0aGUgY29ycmVjdCBwYXNza2V5LCB3ZWxsIGRvbmUh" Creeper215's Easy CrackMe - аналогично, 3-е ветвление в карте с конца это проверка функции от пасса(нужно поменять условие): Код (Text): $+250 00407FE5 $+254 00407FE7 $+258 00407FFF $+25C 00408014 $+260 00405575 $+264 00405584 $+268 00401029 <--- $+26C 0040102B $+270 0040320E $+274 00403222 $+278 00410B54 $+27C 00410B56 $+280 00000000 Код (Text): 00401022 cmp dword ptr ss:[ebp-4],1111F3F 00401029 je short 0040103A На что они надеются собирая такие easy", которые за десяток секунд решаются.. Mojtaba's Crackme! - на VB. В карте 6 условных ветвлений: Код (Text): $ 004020CE app.004020CE $+4 004020E2 app.004020E2 $+8 0040212F app.0040212F <--- $+C 004021F4 app.004021F4 $+10 004021F6 app.004021F6 $+14 00402208 app.00402208 $+18 010F532F $+1C 010F5331 $+20 0040221D app.0040221D $+24 0040222E app.0040222E $+28 00402253 app.00402253 $+2C 00402264 app.00402264 $+30 00000000 Проверка на 2-м: Код (Text): 0040212C cmp di,bx 0040212F je 004021F4 Можно дальше пойти и найти пасс. Для этого посмотреть карту процедурных ветвлений. Код (Text): $+40 004020F6 app.004020F6 $+44 004022D0 Entry address $+48 734E6D92 MSVBVM60.734E6D92 $+4C 0040231A app.0040231A <--- $+50 0040231F app.0040231F - просто пролистав лог: Код (Text): 00402306 mov dword ptr ss:[ebp-28],00401E68 ; UNICODE "8YL4-H4LL-HLAH-WH6R-1K6C" 0040230D mov dword ptr ss:[ebp-30],8 00402314 call dword ptr ds:[<&MSVBVM60.__vbaVarCopy ] 0040231A push 0040232C Это всё просто тк хэш функций нет. А как с ними быть я хз. "crk" пасс.
Я так и не понял чем тебе хеширование не угодило. Найденные тобой ветвления во всех трех примерах находятся самым очевидным детским search for -> referenced strings. У бонифация условное ветвление, которое ты бы нашел, так выглядит (при zf=0 после сравнения хешей получается 0x13^0x09): Код (Text): $7563 MOV AL,BYTE PTR SS:[EBP-14] $7566 XOR AL,BYTE PTR SS:[EBP-13] $7569 CMP AL,1A $756B JNE SHORT $7570 Но оно как бы обслуживает далеко не только это сравнение, это вроде бы должно быть очевидно, если применяется виртуализация.
f13nd, > во всех трех примерах находятся самым очевидным Можно jit посмотреть, что бы было не очевидно. OffsetJud's Crackme Код (Text): $ 033E0B63 $+4 033E0B6A $+8 033E0B9B <--- $+C 033E0BCB $+10 033E0BDB $+14 033E0BF4 $+18 00D5B6C7 $+1C 00D5B6DB $+20 00CB280A $+24 00CB2810 $+28 00CB281E $+2C 00CB2824 $+30 00CB2849 $+34 00CB284B $+38 00CB2876 $+3C 00CB2878 $+40 00CB2880 $+44 00CB2882 $+48 00000000 - то же самое, разве что сборка в буферах нужно искать сигнатурно, тк хз где в исходном образе соответствие. Но если глянуть среду на найденном бранче, то данные для ввода хардкод: - как это решать без декомпилера ? > не только это сравнение Так ведь в принципе условных ветвлений может небыть вообще, проверка валидности хэша, а затем переход к Ip = f(hash). Например Ip = md5(str) + C. Вот и как такое решать, хотя бы сформулировать метод обнаружения хэш-функции.
Если вдруг кому интересно, то во второй крекмише (как и в первой) простая стековая ВМ, без добавления мусора псевдо-код второй крекмиши выглядит так (я еще себе дизасм запилил, чтобы смотреть, как это все компилится и проще было ошибки искать, если накосячу, добавил пару комментов, чтобы было понятнее): Код (Text): # Проверка на патч JMPF # (сравниваются два рандомных неравных числа) 0000 PUSHI 2907363183 (0xAD4AD76F) 0010 PUSHI 75249493 (0x047C3755) 0020 EQ 0022 JMPF 0147 0032 PUSHS "Please don't patch my opcode handlers, bro!" 0082 ECHO 0084 PUSHS "This is so rude of you, please don't, bro!" 0133 ECHO 0135 HALT # Инструкция завершает ВМ 0137 JMP 9999 # На всякий случай, если бы мне еще и HALT решили запатчить # Основная логика 0147 PUSHS "Enter password, bro: " 0175 ECHO 0177 INPUT 0179 STORE index:0 # Начинаем хеш считать 0183 PUSHI 1630981612 (0x6136CDEC) 0193 STORE index:1 0197 LOAD index:0 0201 SLEN 0203 STORE index:2 0207 PUSHI 0 (0x00000000) 0217 STORE index:3 0221 LOAD index:3 0225 LOAD index:2 0229 LT 0231 JMPF 0345 0241 LOAD index:1 0245 PUSHI 2870014623 (0xAB10F29F) 0255 MUL 0257 STORE index:4 0261 LOAD index:0 0265 LOAD index:3 0269 ORD 0271 STORE index:5 0275 LOAD index:4 0279 LOAD index:5 0283 ADD 0285 PUSHI 16777215 (0x00FFFFFF) 0295 AND 0297 STORE index:6 0301 LOAD index:1 0305 LOAD index:6 0309 ADD 0311 STORE index:1 0315 LOAD index:3 0319 PUSHI 1 (0x00000001) 0329 ADD 0331 STORE index:3 0335 JMP 0221 # Сравнение хеша с заранее просчитанным 0345 LOAD index:1 0349 PUSHI 1747247142 (0x6824E026) 0359 EQ 0361 JMPF 0448 # Изначально предполагал патч здесь 0371 PUSHS "Password is valid, bro!" 0401 ECHO 0403 PUSHS "You are real cracker, bro!" 0436 ECHO 0438 JMP 0518 0448 PUSHS "Password is invalid, bro!" 0480 ECHO 0482 PUSHS "Better luck next time, bro!" 0516 ECHO 0518 HALT Компилится псевдо-код из такого кода с помощью моего макроса virtualize, который обходит ast-дерево, компилит дерево в байткод и заменяет его вызовом ВМ (специально сделал исходный кодец без каких-то высокоуровневых конструкций, чтобы проще было компилить, hash_seed - псевдослучайный при каждой сборке, cp_hash_string - тот же хеш, но вычисляется макросом при компиляции еще до виртуализации, компиляция без каких-то оптимизаций байт-кода): Код (Text): proc lowered_function() {. virtualize .} = echo("Enter password, bro: ") var password = read_line(stdin) var xhash = hash_seed var slen = len(password) var i = 0 while i < slen: let v1 = xhash * 0xab10f29f'u32 let v2 = ord(password[i]).uint32 let v3 = (v1 + v2) and 0xffffff'u32 xhash = xhash + v3 i = i + 1 if xhash == cp_hash_string("TestDatVmStuff"): echo("Password is valid, bro!") echo("You are real cracker, bro!") else: echo("Password is invalid, bro!") echo("Better luck next time, bro!")
Большая часть криптографии не имеет математического смысла. Если есть сдвиги (особенно циклические) больше чем на 3 бита, если есть конъюнкции/дизъюнкции/строгие дизъюнкции с длинными битовыми полями, то как бы очевидно, что это криптография. Код (Text): private void button1_Click(object sender, EventArgs e) { bool flag = this.textBox1.Text == "kekstra" && this.textBox2.Text == "topkek"; if (flag) { MessageBox.Show("Congratz negro!", "Get some bitches on yo dick"); } else { MessageBox.Show("You are a dumb ass and you'll never learn reverse engineering :'(", "What a failure!"); } } Хз. Наверное очень грустно дотнет без декомпилера решать. Хотя секундочку: Код (Text): seg000:0081 ldarg.0 seg000:0082 ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox crackmeTVLPA.Form1::textBox1 seg000:0087 callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text() seg000:008C ldstr aKekstra // "kekstra" seg000:0091 call bool [mscorlib]System.String::op_Equality(string, string) seg000:0096 brfalse.s loc_AF seg000:0098 ldarg.0 seg000:0099 ldfld class [System.Windows.Forms]System.Windows.Forms.TextBox crackmeTVLPA.Form1::textBox2 seg000:009E callvirt instance string [System.Windows.Forms]System.Windows.Forms.Control::get_Text() seg000:00A3 ldstr aTopkek // "topkek" seg000:00A8 call bool [mscorlib]System.String::op_Equality(string, string) seg000:00AD br.s loc_B0 seg000:00AF seg000:00AF // CODE XREF: crackmeTVLPA.Form1__button1_Click+16↑j seg000:00AF ldc.i4.0 seg000:00B0 seg000:00B0 // CODE XREF: crackmeTVLPA.Form1__button1_Click+2D↑j seg000:00B0 stloc.0 seg000:00B1 ldloc.0 seg000:00B2 brfalse.s loc_C8 seg000:00B4 nop seg000:00B5 ldstr aCongratzNegro // "Congratz negro!" seg000:00BA ldstr aGetSomeBitches // "Get some bitches on yo dick" seg000:00BF call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string) seg000:00C4 pop seg000:00C5 nop seg000:00C6 br.s loc_DA seg000:00C8 seg000:00C8 // CODE XREF: crackmeTVLPA.Form1__button1_Click+32↑j seg000:00C8 nop seg000:00C9 ldstr aYouAreADumbAss // "You are a dumb ass and you'll never lea"... seg000:00CE ldstr aWhatAFailure // "What a failure!" seg000:00D3 call valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string, string) seg000:00D8 pop seg000:00D9 nop seg000:00DA seg000:00DA // CODE XREF: crackmeTVLPA.Form1__button1_Click+46↑j seg000:00DA ret Тоже можно.
Для крипты и вирты автоматика бесполезна. Если тем же инструментом прогнать Rel, семпл, вот что получается: Код (Text): $ kernel32.7C872ADA $+4 app.004082F3 $+8 app.00408305 $+C app.00408443 $+10 app.00408447 $+14 app.0040849C $+18 app.004084B0 $+1C Entry address $+20 app.00401CF0 $+24 app.00407ABA $+28 app.00407AA4 $+2C app.00407B9C $+30 app.00407BEC $+34 app.004084B5 $+38 app.004018C4 $+3C app.004084C6 $+40 app.004084CF $+44 Entry address $+48 msvcrt.77C1C2E3 $+4C app.00401C12 $+50 app.00401C13 $+54 app.004084D4 $+58 app.004084D7 $+5C app.004086FF $+60 app.0040705D $+64 app.00408741 $+68 app.00407188 $+6C app.00408759 $+70 app.004019BB $+74 app.00408763 $+78 app.004018C4 $+7C app.0040876B $+80 app.00409998 <--- $+84 app.00407786 $+88 app.0040162A $+8C app.004077A0 $+90 app.004073F8 $+94 app.004077AA $+98 app.004016AE $+9C app.004077BD $+A0 app.00402652 $+A4 app.004072CB $+A8 app.004072D9 $+AC app.004077DD $+B0 app.004070F1 $+B4 app.004077FA $+B8 app.004019BB $+BC app.00407805 $+C0 app.00409998 <--- $+C4 app.004071E5 $+C8 app.0040162A $+CC app.004071FD $+D0 app.004016AE $+D4 app.00407204 $+D8 app.0040162A $+DC app.0040721E $+E0 app.004070F1 $+E4 app.00407244 $+E8 app.00407188 $+EC app.0040726E $+F0 app.004019BB $+F4 app.00407279 $+F8 app.00409998 <--- $+FC app.00407618 $+100 app.0040162A $+104 app.00407633 $+108 app.0040162A $+10C app.0040763B $+110 app.0040162A $+114 app.00407642 $+118 app.004073F8 $+11C app.00407652 $+120 app.004073F8 $+124 app.0040766A $+128 app.00401AFF $+12C app.0040767F $+130 app.00407188 $+134 app.0040768E $+138 app.00401B0D $+13C app.00407698 $+140 app.00401B0D $+144 app.004076A0 $+148 app.00401B0D $+14C app.004076A8 $+150 app.00409998 <--- $+154 app.004076B0 $+158 app.0040162A $+15C app.004076CB $+160 app.0040162A $+164 app.004076D3 $+168 app.0040162A $+16C app.004076DA $+170 app.004073F8 $+174 app.004076EA $+178 app.004073F8 $+17C app.00407702 $+180 app.00401A9C $+184 app.0040771D $+188 app.00407188 $+18C app.0040772C $+190 app.00401B0D $+194 app.00407736 $+198 app.00401B0D $+19C app.0040773E $+1A0 app.00401B0D $+1A4 app.00407746 $+1A8 app.00409998 <--- $+1AC app.00407E4A $+1B0 app.0040162A $+1B4 app.00407E62 $+1B8 app.0040162A $+1BC app.00407E78 $+1C0 app.0040162A $+1C4 app.00407E80 $+1C8 app.004073F8 $+1CC app.00407E90 $+1D0 app.004073F8 $+1D4 app.00407EAF $+1D8 app.00407DB2 $+1DC app.00407EBE $+1E0 app.00401AFF $+1E4 app.00407ED9 $+1E8 app.00407188 $+1EC app.00407EE8 $+1F0 app.00401B0D $+1F4 app.00407EF3 $+1F8 app.004019BB $+1FC app.00407EFB $+200 app.004018C4 $+204 app.00407F03 $+208 app.00401B0D $+20C app.00407F0B $+210 app.00409998 <--- ORD $+214 app.004016AF $+218 app.0040167A $+21C app.004016BA $+220 app.00409998 <--- $+224 app.004015FB $+228 app.004019BB $+22C app.00409940 $+230 app.00409943 $+234 Entry address $+238 app.004019BB $+23C app.00401BE5 $+240 msvcrt.77C1C2E3 $+244 app.00401BF6 $+248 app.00401BFC $+24C app.00409948 $+250 app.00401BFC $+254 app.00409950 $+258 app.004019BB $+25C app.00409958 $+260 app.004099A7 $+264 Entry address $+268 app.00402456 $+26C app.004099AC $+270 msvcrt.77C1C2E3 $+274 app.004099DE $+278 app.00409A32 $+27C app.00410AF3 $+280 app.00410AFE $+284 app.00401396 $+288 app.0040149E $+28C Entry address $+290 - выделяется цикл вирты и стабы их 7. Карта строится после ввода, то стабы при инит. скипаются. PUSHI EQ JMPF PUSHS ECHO INPUT Должно остаться 9: STORE LOAD SLEN LT MUL ORD ADD AND JMP - два куда то потерялись, значит вызываются ранее. Можно весь код покрыть при запуске апп запустить карт., но это всё бесполезно и ничего не даёт. Вирту решать можно исключительно разбирая вручную, аналогично как и с хэшами.
f13nd, Там где вирты нет норм работает, в вирте не исполнение, а чтение кодовой последовательности которое может быть совершенно произвольным; такое наверно в принципе нельзя как то автоматикой решать. Вручную ковырять семплы это время тратить впустую имхо.
Ну вот все 4 семпла, которые ты показал, вообще никаких визоров не требовали, разобраться в них буквально за минуту можно. Кто впустую потратил время?
f13nd, Так сложность значение имеет лишь для ручного разбора. Два более сложных - net/vb ты ведь отладчиком не решил, для первого использовал декомп. Для вб тоже декомп нужен ? Я глянул псевдокод #134, очень калк спекки напоминает - стек, индексные регистры.. Код (Text): i0 = S$ i1 = 0x6136CDEC i2 = LEN(i0) i3 = 0 #221: LT(i2, i3) -> #345 i4 = 0xAB10F29F * i1 i5 = i0 | i3 i6 = (i4 + i5) & 0x00FFFFFF i1 = i1 + i6 i3 = i3 + 1 > #221 Если упростить, получается: Код (Text): i1 = 0x6136CDEC !i3 #221: LT(LEN(S$), i3) -> #345 i1 + ((0xAB10F29F * i1 + (S$ | i3)) & 0x00FFFFFF) i3 ++ > #221 - функция необратима. На что рел надеялся, те как строку искать, вечным брутом ?