Jump to content
Tuts 4 You

[unpackme] Armadillo v6.0.4 Custom Build


acidflash

Recommended Posts

ok, but don't expect to hear from me too soon....

on my "to-do-list" secured sections are on place... oh! seems they aren't on my list at all :lol:

have to add them the other day....

till then!

btw. - i think you're a nice guy (even though you keep your knowledge :D or should i say BECAUSE you keep your knowledge?) - so c.u. in another thread!

XytroX

Link to comment
Share on other sites

man, i seriously gotta think about an e-peen enlargement :geek:

don't take my last post too serious - what i want to say is: don't expect to hear from me at all.

"to-do-list" is related to things i have to do in real life.

but maybe i get you wrong? sorry if i misunderstood.i think my english isn't the best.

XytroX

Edited by XytroX
Link to comment
Share on other sites

Your English is perfectly fine :D

I was just referring to the general "I can do things others can't", people always seem to compare their dicks against others...

That's no criticism, I just think it's another reason why that kind of stuff usually remains private.

Edited by Killboy
Link to comment
Share on other sites

Your English is perfectly fine :D

i am sure it isn't at all but thank you anyway

I was just referring to the general "I can do things others can't", people always seem to compare their dicks against others...

That's no criticism, I just think it's another reason why that kind of stuff usually remains private.

ahh! i see. well, sorry if one can read that statement out of my words.

to make it clear:

i think that fungus did an extremely good job on this protection. and i am quite sure that i will never know how to

go around this. but please: don't discourage me, ok? :)

i just try to be a little bit self-deprecating - my fault. i do such things rather in german than in english. :(

sorry for that!

i think i leave a bad mark....

but better stop getting too much offtopic now.

XytroX

Link to comment
Share on other sites

  • 3 years later...

interesting

username:apuromafo

key:000013-KEG2FA-28EQ7U-KDNY8V-ZZFZZZ-ZZZZZZ-ZWCJP9-51VJ00-800000-000000

---------------------------

Information

---------------------------

Program is registered to apuromafo (000017-KEG2FA-28EQ7U-KDNY8V-ZZFZZZ-ZZZZZZ-ZWCJP9-51VJ00-800000-000000).

---------------------------

Aceptar

---------------------------

Link to comment
Share on other sites

As the method I know died:

1) Find arma certificate (should be available to public)

2) Brute force all certs (multi-threaded bruter available)

3) Replace lvl10 public vals/patch ecdsa_verify/ngen (dont know how)

4) Paste stuff in ArmaKG.exe from vel

5) Enter key in (patched) exe

6) Unpack as usual

Link to comment
Share on other sites

this app is vulnerable to ngen (ecsa valid when infinite point = 0) check armadillo keygen and 2 serial to check:

method done:

1) Find arma certificate (should be available to public)->done

2) Brute force all certs (multi-threaded bruter available)->done

3) using the kgonly for lv10(there in last time see this in LNDL, and others keygens with hiw, and changing only the value (checksum valid), will do a key,

160TB01NQNDQVQG00000000000000000000000000000000000000000000--->crash

^^

when put the serial : there unlock the secured sections! as if check my username and serial

**4) Paste stuff in ArmaKG.exe from vel->nop, not used in this case

4) unpack as alwais ^^

amm for 3 is this:

Hi, sorry to re-up this old thread but I'm curious to know the version of ArmaFP you used to get informations on certificates, especially the private key.

There is no reason a protected app contain the private key and I've never seen any private key during my different arma analysis.

By the way, Armadillo verification scheme with ecdsa can be broken (for some versions of arma, all < 7 I think) because of a bad implementation of this algorithm

There is no verification of the return value of the function which inverse y (where the sig is (x,y)), so you can specify a y = n, "inversed" as n = 0 mod n so :

(i,j) = (H(m)y^(-1) mod n)G + (xy^(-1) mod n)Q

become :

(i,j) = 0G + 0Q = infinite point

So to have a "valid" signature all you have to do is to use the signature (infinite_point.x, n).

To check if a version of arma is vulnerable, just enter those 2 serial : 160TB01NQNDQVQG00000000000000000000000000000000000000000000 and 16YNPZEZG6AR0D77UKDNY8VZZFZZZZZZZZZZWCJP951VJ00800000000000

If application crash with the first one but not with the second then there is lot of chance it's vulnerable.

This bug has been "patched" in more recent versions of armadillo, now arma crash if y = 0 or n...

This is this bug which is explained on my blog you linked in your previous post, all you have to do to keygen a vulnerable arma protected app is to find the private key.

Edited by Apuromafo
Link to comment
Share on other sites

The symmetric is used as one of the seeds for building the 0x400 byte table. This table is hashed with MD5 and the resulting hash is the key used for decrypting the certificate descriptors, the containers which hold offset and key (amongst other things ofc) of every secure section the certificate has access to.

For unpacking any application with secure sections these need to be recovered and imho the vulnerability which was spoken of is the succeptibility to keygenning...

The only approach i've seen is:

ElGamal - Solve DLP using public values recovered from protected file.

ECDSA - Patch ECDSA_Verify, replace certificate values or create bogus key a-la baboon's method.

Symmetric Key: Bruteforcer { Multithreaded CPU or CUDA GPU based }

Symmetric Key: Rainbow table (16gb file) lookup, killed with newer 1000 round md5 + salt.

A 'valid' key is formed and used to register the application, then the file is unpacked with secure sections restored automatically at runtime.

I did toy with the idea of a bruteforcer to decrypt the secure sections (recovering the encrypted code is trivial but recovering the address and key is not, due to the fact the certificate descriptor are encrypted), whereby it would try to find the 32 bit key needed to decrypt the code. The method was as follows:

1. Create copy of encrypted code for (ab)use in current iteration.

2. Increment 32 bit current key.

3. Using copy of current key (it gets changed during decryption, thus the need to preserve its value for incrementing), loop through xoring each byte of the copy with the return value of 'NextRandomRange(Key, 0x100)'.

4. Attempt to disassemble forwards starting at offset 00, if the disassembly fails then decryption also failed, if the disassembly made it to the end of the code and EIP would land on the next byte (making the entire buffer 'valid' code) then decryption succeeded.

5. Report success or loop through steps until either valid key is found OR 0x00000000 - 0xFFFFFFFF has been searched (report failure).

Apparently, although the code is garbage when an incorrect key is used to decrypt, there are still many combinations that can be disassembled AND match the length requirement. I say this because on the concept tester i made for this there were so many 'valid' hits it wasn't funny and i immediately knew that there was no way i could use this method, i would probably have less time waste and trouble if i were to simply do the bruteforcing manually inside Olly even though it would mean having to check the buffer on every decrypt attempt.

HR,

Ghandi

Edited by ghandi
  • Like 2
Link to comment
Share on other sites

chickenbutt

FYI..Secure Sections has an identical rng padding bug as some other up-to-date protectors. Except here it's used on encryption rather than a keygen.

I will give silicon realms this, they are at least the first vendor do this, others are still going with runtime decyrption and a lot of mutations and instruction handlers which can all be defeated through common tracing and dumping methods. If it wasn't for this bug your only option would be to brute a lot of data.

Link to comment
Share on other sites

FYI..Secure Sections has an identical rng padding bug as some other up-to-date protectors.

heard of this...is there more info available?

Link to comment
Share on other sites

chickenbutt

I only know because of conversations of some of math people in the scene. It's the same with winlicense RSA. Once they all fix it only leaked keys and/or major GFLOPS will defeat them.

Link to comment
Share on other sites

well, the principal theme about armadillo is talked, but other question involved..exist a method there use not the checksum, and use the value of tean? that'?

Link to comment
Share on other sites

There is a way:

brutertean.png

bruter does something like this (I don't know much)

1) need custom crc values

2) increasing checksum (needs to brute checksum??, think its another one)

3) some calculations (xor,and,imul)

4) crc those values (from different calculations)

5) build a buffer with increasing ebx till == CustCRC2

6) md5(hash,buffer,0x400)

7) get first md5 dword and and with 0x7

8) if that is equal to the first byte of securesection data go next, other go to step 1 with increased checksum

9) I dont understand, something with TEAN and NOT of checksum, xor with crc1

Source code is not from me so I cannot send it sad.png

Edited by Mr. eXoDia
  • Like 1
Link to comment
Share on other sites

It is not bruteforcing secure sections at all, it is bruteforcing the actual certificate data which contains the keys and offsets for the secure sections.

If/when it succeeds it provides a symmetric key which you use in a keygenerator, then you have access to the secure sections OR if you want to get a little more technical you could always extract the keys and offsets, then recover the data and decrypt them yourself, horses for courses.

The secure section data is stored at the end of the PDATA section, with a WORD to denote the size of the data followed by the encrypted data. When unpacking, Armadillo checks to see if the certificate loaded has access to any sections and if so it extracts and decrypts it/them to the image.

This is taken from this actual unpackme:


00A35391 B9 04000000 mov ecx,4 ; Load index into table
00A35396 C1E1 02 shl ecx,2 ; Multiply by 4 to make offset into table
00A35399 8B15 2C0BAA00 mov edx,dword ptr [AA0B2C] ; Load table
00A3539F 8B040A mov eax,dword ptr [edx+ecx] ; Load dword from table
00A353A2 83F0 00 xor eax,0 ; ? Filler ?
00A353A5 8945 C0 mov dword ptr [ebp-40],eax ; Save dword for later use <DWORD_1>
00A353A8 B9 1B000000 mov ecx,1B ; Load index into table
00A353AD C1E1 02 shl ecx,2 ; Multiply by 4 to make offset into table
00A353B0 8B15 2C0BAA00 mov edx,dword ptr [AA0B2C] ; Load table
00A353B6 8B040A mov eax,dword ptr [edx+ecx] ; Load dword from table
00A353B9 83F0 00 xor eax,0 ; ? Filler ?
00A353BC 25 FF1F0000 and eax,1FFF ; Mask off bits
00A353C1 05 88130000 add eax,1388 ; Add 0x1388 to make counter for second loop
00A353C6 8945 C4 mov dword ptr [ebp-3C],eax ; Save dword for later use <DWORD_2>
00A353C9 8B4D 0C mov ecx,dword ptr [ebp+C] ; Load symmetric to test
00A353CC 894D E0 mov dword ptr [ebp-20],ecx ; Save for later use <DWORD_3>
00A353CF 8D95 A8FBFFFF lea edx,dword ptr [ebp-458] ; Load pointer to 0x400 table
00A353D5 8955 D8 mov dword ptr [ebp-28],edx ; Save pointer for later use
00A353D8 C745 EC 0000000>mov dword ptr [ebp-14],0 ; Set counter to 0
00A353DF 8B45 E0 mov eax,dword ptr [ebp-20] ; Load symmetric to test
00A353E2 3345 C0 xor eax,dword ptr [ebp-40] ; Xor with <DWORD_1>
00A353E5 8945 B0 mov dword ptr [ebp-50],eax ; Save dword for later use <DWORD_4>
00A353E8 8B4D E0 mov ecx,dword ptr [ebp-20] ; Load symmetric to test
00A353EB 894D F0 mov dword ptr [ebp-10],ecx ; Save dword for later use <DWORD_5>
00A353EE 8B55 E0 mov edx,dword ptr [ebp-20] ; Load symmetric to test
00A353F1 3355 C0 xor edx,dword ptr [ebp-40] ; Xor with dword 1
00A353F4 6BD2 0A imul edx,edx,0A ; Multiply by 10
00A353F7 83C2 01 add edx,1 ; Increment by 1
00A353FA 8955 B8 mov dword ptr [ebp-48],edx ; Save dword for later use <DWORD_6>
00A353FD C745 EC 0000000>mov dword ptr [ebp-14],0 ; Set counter to 0 again
00A35404 EB 09 jmp short 00A3540F ; Enter for(; loop
00A35406 8B45 EC mov eax,dword ptr [ebp-14] ; Load counter
00A35409 83C0 01 add eax,1 ; Increment counter by 1
00A3540C 8945 EC mov dword ptr [ebp-14],eax ; Save new counter value
00A3540F 817D EC 0001000>cmp dword ptr [ebp-14],100 ; Loop for 0x100 iterations
00A35416 73 31 jnb short 00A35449 ; Then exit loop
00A35418 8D4D B0 lea ecx,dword ptr [ebp-50] ; Load pointer to <DWORD_4>
00A3541B E8 40160000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_4>
00A35420 8BF0 mov esi,eax ; ESI = <CURRENT_DWORD>
00A35422 8D4D F0 lea ecx,dword ptr [ebp-10] ; Load pointer to <DWORD_5>
00A35425 E8 36160000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_5>
00A3542A 33F0 xor esi,eax
00A3542C 8D4D B8 lea ecx,dword ptr [ebp-48] ; Load pointer to <DWORD_6>
00A3542F E8 2C160000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_6>
00A35434 33F0 xor esi,eax
00A35436 3375 E0 xor esi,dword ptr [ebp-20] ; Xor <CURRENT_DWORD> with <DWORD_3>
00A35439 8B4D D8 mov ecx,dword ptr [ebp-28] ; Load current pointer into table
00A3543C 8931 mov dword ptr [ecx],esi ; Save dword to table at current position
00A3543E 8B55 D8 mov edx,dword ptr [ebp-28] ; Load current pointer to table
00A35441 83C2 04 add edx,4 ; Increment by 4 to point to next entry
00A35444 8955 D8 mov dword ptr [ebp-28],edx ; Save current pointer to table
00A35447 ^ EB BD jmp short 00A35406 ; Cycle the first loop to fill the table with initial values
00A35449 6A 10 push 10 ; Range = 0 - F
00A3544B 8D4D B0 lea ecx,dword ptr [ebp-50] ; Load pointer to <DWORD_4>
00A3544E E8 4DDBFEFF call <NextRandomRange> ; Get next random range based on seed <DWORD_4>
00A35453 8BF0 mov esi,eax ; Save for next part
00A35455 6A 10 push 10 ; Range = 0 - F
00A35457 8D4D F0 lea ecx,dword ptr [ebp-10] ; Load pointer to <DWORD_5>
00A3545A E8 41DBFEFF call <NextRandomRange> ; Get next random range based on seed <DWORD_5>
00A3545F 03F0 add esi,eax ; Add to saved result to make <SHR_COUNT>
00A35461 89B5 A4FBFFFF mov dword ptr [ebp-45C],esi ; Save dword for later use <SHR_COUNT>
00A35467 C745 EC 0000000>mov dword ptr [ebp-14],0 ; Reset loop counter
00A3546E EB 09 jmp short 00A35479 ; Enter for(; loop
00A35470 8B45 EC mov eax,dword ptr [ebp-14] ; Load counter
00A35473 83C0 01 add eax,1 ; Increment counter by 1
00A35476 8945 EC mov dword ptr [ebp-14],eax ; Save new counter value
00A35479 8B4D EC mov ecx,dword ptr [ebp-14] ; Load current counter value
00A3547C 3B4D C4 cmp ecx,dword ptr [ebp-3C] ; Compare with <DWORD_2> <LOOP_COUNTER_2>
00A3547F 0F83 AB000000 jnb 00A35530 ; Exit loop when equal or above (NOT BELOW)
00A35485 8B55 EC mov edx,dword ptr [ebp-14] ; Load counter
00A35488 81E2 FF000000 and edx,0FF ; Mask off all but lower byte to give index into table
00A3548E 75 09 jnz short 00A35499 ; Jump over if not zero
00A35490 8D85 A8FBFFFF lea eax,dword ptr [ebp-458] ; Reload pointer to table
00A35496 8945 D8 mov dword ptr [ebp-28],eax ; Resave pointer for use
00A35499 8B4D D8 mov ecx,dword ptr [ebp-28] ; Load current pointer to table
00A3549C 8B11 mov edx,dword ptr [ecx] ; Get current dword from table
00A3549E 8B8D A4FBFFFF mov ecx,dword ptr [ebp-45C] ; Load <SHR_COUNT>
00A354A4 D3EA shr edx,cl ; Shift EDX right by <SHR_COUNT> value
00A354A6 83E2 03 and edx,3 ; Mask off all but 3 to get case for switch
00A354A9 8995 9CFBFFFF mov dword ptr [ebp-464],edx ; Save result
00A354AF 75 25 jnz short 00A354D6 ; Skip if not zero
00A354B1 8D4D B0 lea ecx,dword ptr [ebp-50] ; Load pointer to <DWORD_4>
00A354B4 E8 A7150000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_4>
00A354B9 8B4D D8 mov ecx,dword ptr [ebp-28] ; Load current pointer to table
00A354BC 0B01 or eax,dword ptr [ecx] ; OR EAX with current dword from table
00A354BE 8B55 D8 mov edx,dword ptr [ebp-28] ; Load current pointer to table
00A354C1 8902 mov dword ptr [edx],eax ; Save new dword to table
00A354C3 8B45 D8 mov eax,dword ptr [ebp-28] ; Load current pointer to table
00A354C6 83C0 04 add eax,4 ; Increment pointer to next entry
00A354C9 8945 D8 mov dword ptr [ebp-28],eax ; Save new pointer to table
00A354CC 8D4D F0 lea ecx,dword ptr [ebp-10] ; Load pointer to <DWORD_5>
00A354CF E8 8C150000 call <NextRandomNumber> ; Call NextRandomNumber to cycle the seed <DWORD_5>
00A354D4 EB 55 jmp short 00A3552B ; Jump to loop jump
00A354D6 83BD 9CFBFFFF 0>cmp dword ptr [ebp-464],1 ; Check case result for 1
00A354DD 75 25 jnz short 00A35504 ; Jump to CASE 2: statement
00A354DF 8D4D F0 lea ecx,dword ptr [ebp-10] ; Load pointer to <DWORD_5>
00A354E2 E8 79150000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_5>
00A354E7 8B4D D8 mov ecx,dword ptr [ebp-28] ; Load current pointer to table
00A354EA 2301 and eax,dword ptr [ecx] ; AND EAX with current dword from table
00A354EC 8B55 D8 mov edx,dword ptr [ebp-28] ; Load current pointer to table
00A354EF 8902 mov dword ptr [edx],eax ; Save new dword to table
00A354F1 8B45 D8 mov eax,dword ptr [ebp-28] ; Load current pointer to table
00A354F4 83C0 04 add eax,4 ; Increment pointer to next entry
00A354F7 8945 D8 mov dword ptr [ebp-28],eax ; Save new pointer to table
00A354FA 8D4D B0 lea ecx,dword ptr [ebp-50] ; Load pointer to <DWORD_4>
00A354FD E8 5E150000 call <NextRandomNumber> ; Call NextRandomNumber to cycle the seed <DWORD_4>
00A35502 EB 27 jmp short 00A3552B ; Jump to loop jump
00A35504 8D4D B0 lea ecx,dword ptr [ebp-50] ; Load pointer to <DWORD_4>
00A35507 E8 54150000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_4>
00A3550C 8BF0 mov esi,eax ; Save for next part
00A3550E 8D4D F0 lea ecx,dword ptr [ebp-10] ; Load pointer to <DWORD_5>
00A35511 E8 4A150000 call <NextRandomNumber> ; Get next number in cycle based on seed <DWORD_5>
00A35516 33F0 xor esi,eax ; XOR result with saved result to make new entry seed
00A35518 8B4D D8 mov ecx,dword ptr [ebp-28] ; Load current pointer to table
00A3551B 3331 xor esi,dword ptr [ecx] ; XOR ESI with current dword from table
00A3551D 8B55 D8 mov edx,dword ptr [ebp-28] ; Load current pointer to table
00A35520 8932 mov dword ptr [edx],esi ; Save new dword to table
00A35522 8B45 D8 mov eax,dword ptr [ebp-28] ; Load current pointer to table
00A35525 83C0 04 add eax,4 ; Increment pointer to next entry
00A35528 8945 D8 mov dword ptr [ebp-28],eax ; Save new table pointer
00A3552B ^ E9 40FFFFFF jmp 00A35470 ; Loop for <DWORD_2> count
00A35530 68 00040000 push 400 ; Push the size of the table
00A35535 8D8D A8FBFFFF lea ecx,dword ptr [ebp-458] ; Load the pointer to the table
00A3553B 51 push ecx ; Push it
00A3553C 8D55 C8 lea edx,dword ptr [ebp-38] ; Load the pointer to the MD5 result
00A3553F 52 push edx ; Push it
00A35540 E8 EB090200 call 00A55F30 ; Get the MD5 of the table
00A35545 83C4 0C add esp,0C ; Correct the stack after __cdecl call
00A35548 8B45 E0 mov eax,dword ptr [ebp-20] ; Load symmetric
00A3554B F7D0 not eax ; Not it
00A3554D 3345 C0 xor eax,dword ptr [ebp-40] ; XOR it with <DWORD_1>
00A35550 8945 B4 mov dword ptr [ebp-4C],eax ; Save as a new seed for NextRandomRange
00A35553 68 90010000 push 190 ; Range = 0 - 399 decimal
00A35558 8D4D B4 lea ecx,dword ptr [ebp-4C] ; Load pointer to new seed
00A3555B E8 40DAFEFF call <NextRandomRange> ; Get next range in cycle based on new seed
00A35560 05 21030000 add eax,321 ; ADD 321 to result to make <TEAN_LOOP_COUNT>
00A35565 8945 AC mov dword ptr [ebp-54],eax ; Save result
00A35568 8B4D C8 mov ecx,dword ptr [ebp-38] ; Load first dword of MD5 result
00A3556B 83E1 07 and ecx,7 ; AND with 7 to get <GENERATED_CERTIFICATE_GROUP>
00A3556E 884D F7 mov byte ptr [ebp-9],cl ; Save result <GENERATED_CERTIFICATE_GROUP>
00A35571 C645 FF 00 mov byte ptr [ebp-1],0 ; Set boolean flag to FALSE
00A35575 8B15 E804AA00 mov edx,dword ptr [AA04E8] ; Load pointer to certificate information (encrypted)
00A3557B 8955 F8 mov dword ptr [ebp-8],edx ; Save to local <NEXT_CERTIFICATE>
00A3557E 0FB645 FF movzx eax,byte ptr [ebp-1] ; Load boolean flag
00A35582 85C0 test eax,eax ; Check if it is 0
00A35584 0F85 6A140000 jnz 00A369F4 ; Exit loop if not zero
00A3558A 8B0D E404AA00 mov ecx,dword ptr [AA04E4] ; Load pointer to end of encrypted certificate chunks
00A35590 898D 28F8FFFF mov dword ptr [ebp-7D8],ecx ; Save to local <END_CERTIFICATE>
00A35596 8B55 F8 mov edx,dword ptr [ebp-8] ; Load current pointer to certificate data
00A35599 3B95 28F8FFFF cmp edx,dword ptr [ebp-7D8] ; Compare with <END_CERTIFICATE>
00A3559F 0F83 4F140000 jnb 00A369F4 ; Exit loop if not below
00A355A5 8D85 84FBFFFF lea eax,dword ptr [ebp-47C] ; Load pointer to buffer to receive dword <SIZE_OF_CHUNK>
00A355AB 50 push eax ; Push it
00A355AC 8B4D F8 mov ecx,dword ptr [ebp-8] ; Load current pointer to certificate data
00A355AF 51 push ecx ; Push it
00A355B0 E8 5BEF0000 call 00A44510 ; Call wrapper around GetLong
00A355B5 83C4 08 add esp,8 ; Correct stack after __cdecl call
00A355B8 8945 F8 mov dword ptr [ebp-8],eax ; Save new pointer to certificate data
00A355BB 83BD 84FBFFFF 0>cmp dword ptr [ebp-47C],0 ; Check if <SIZE_OF_CHUNK> is zero
00A355C2 75 05 jnz short 00A355C9 ; Continue if not
00A355C4 E9 2B140000 jmp 00A369F4 ; Exit loop if zero
00A355C9 8D95 8FFBFFFF lea edx,dword ptr [ebp-471] ; Load pointer to buffer to receive byte <CERTIFICATE_GROUP>
00A355CF 52 push edx ; Push it
00A355D0 8B45 F8 mov eax,dword ptr [ebp-8] ; Load current pointer to certificate data
00A355D3 50 push eax ; Push it
00A355D4 E8 F7EE0000 call 00A444D0 ; Call wrapper around GetChar
00A355D9 83C4 08 add esp,8 ; Correct stack after __cdecl call
00A355DC 8945 F8 mov dword ptr [ebp-8],eax ; Save new pointer to certificate data
00A355DF 0FB64D F7 movzx ecx,byte ptr [ebp-9] ; Load <GENERATED_CERTIFICATE_GROUP>
00A355E3 0FB695 8FFBFFFF movzx edx,byte ptr [ebp-471] ; Load <CERTIFICATE_GROUP>
00A355EA 3BCA cmp ecx,edx ; Check if equal
00A355EC 74 0E je short 00A355FC ; Continue if so
00A355EE 8B45 F8 mov eax,dword ptr [ebp-8] ; Load current pointer to certificate data
00A355F1 0385 84FBFFFF add eax,dword ptr [ebp-47C] ; Add <CHUNK_SIZE> to pointer to load next entry (if any)
00A355F7 8945 F8 mov dword ptr [ebp-8],eax ; Save new pointer to certificate data
00A355FA ^ EB 82 jmp short 00A3557E ; Cycle the certificate data until a match is found or all are checked
00A355FC 8B8D 84FBFFFF mov ecx,dword ptr [ebp-47C] ; Load <CHUNK_SIZE>
00A35602 51 push ecx ; Push it
00A35603 E8 F7680400 call <malloc> ; Call malloc to allocate memory
00A35608 83C4 04 add esp,4 ; Correct stack after __cdecl call
00A3560B 8985 38FBFFFF mov dword ptr [ebp-4C8],eax ; Save pointer to new memory
00A35611 8B95 38FBFFFF mov edx,dword ptr [ebp-4C8] ; Load pointer to new memory
00A35617 8995 90FBFFFF mov dword ptr [ebp-470],edx ; Save pointer to new memory (again)
00A3561D 8B85 90FBFFFF mov eax,dword ptr [ebp-470] ; Load pointer to new memory
00A35623 8985 98FBFFFF mov dword ptr [ebp-468],eax ; Save pointer to new memory (again)
00A35629 8B8D 84FBFFFF mov ecx,dword ptr [ebp-47C] ; Load <CHUNK_SIZE>
00A3562F 51 push ecx ; Push it
00A35630 8B55 F8 mov edx,dword ptr [ebp-8] ; Load current pointer to certificate data
00A35633 52 push edx ; Push it
00A35634 8B85 90FBFFFF mov eax,dword ptr [ebp-470] ; Load pointer to new memory
00A3563A 50 push eax ; Push it
00A3563B E8 00610400 call <memcpy> ; Copy memory from current certificate chunk to new memory
00A35640 83C4 0C add esp,0C ; Correct stack after __cdecl call
00A35643 8B4D F8 mov ecx,dword ptr [ebp-8] ; Load current pointer to certifcate data
00A35646 038D 84FBFFFF add ecx,dword ptr [ebp-47C] ; Add <CHUNK_SIZE> to pointer to load next entry (if any)
00A3564C 894D F8 mov dword ptr [ebp-8],ecx ; Save new pointer to certificate data
00A3564F 6A FF push -1 ; Push mode ECB Decrypt
00A35651 8B95 84FBFFFF mov edx,dword ptr [ebp-47C] ; Load <CHUNK_SIZE>
00A35657 52 push edx ; Push it
00A35658 8B85 98FBFFFF mov eax,dword ptr [ebp-468] ; Load pointer to new memory
00A3565E 50 push eax ; Push it
00A3565F 8D4D C8 lea ecx,dword ptr [ebp-38] ; Load pointer to MD5 result <TEAN_KEY>
00A35662 51 push ecx ; Push it
00A35663 E8 98560400 call <TeanRounds> ; Call TeanRounds
00A35668 83C4 10 add esp,10 ; Correct stack after __cdecl call
00A3566B C745 EC 0000000>mov dword ptr [ebp-14],0 ; Reset loop counter to 0
00A35672 EB 09 jmp short 00A3567D ; Enter for(;; loop
00A35674 8B55 EC mov edx,dword ptr [ebp-14] ; Load counter
00A35677 83C2 01 add edx,1 ; Increment counter by 1
00A3567A 8955 EC mov dword ptr [ebp-14],edx ; Save new counter
00A3567D 8B45 EC mov eax,dword ptr [ebp-14] ; Load current counter
00A35680 3B45 AC cmp eax,dword ptr [ebp-54] ; Compare with <TEAN_LOOP_COUNT>
00A35683 73 42 jnb short 00A356C7 ; Exit if not below
00A35685 81BD 84FBFFFF 0>cmp dword ptr [ebp-47C],400 ; Compare <CHUNK_SIZE> with 0x400
00A3568F 73 0E jnb short 00A3569F ; If above, jump to set 0x400 count
00A35691 8B8D 84FBFFFF mov ecx,dword ptr [ebp-47C] ; Load <CHUNK_SIZE>
00A35697 898D 1CF8FFFF mov dword ptr [ebp-7E4],ecx ; Save for <TEAN_LOOP_CHUNK_SIZE>
00A3569D EB 0A jmp short 00A356A9 ; Continue
00A3569F C785 1CF8FFFF 0>mov dword ptr [ebp-7E4],400 ; Save 0x400 for <TEAN_LOOP_CHUNK_SIZE>
00A356A9 6A 00 push 0 ; Push mode CBC Decrypt
00A356AB 8B95 1CF8FFFF mov edx,dword ptr [ebp-7E4] ; Load <TEAN_LOOP_CHUNK_SIZE>
00A356B1 52 push edx ; Push it
00A356B2 8B85 98FBFFFF mov eax,dword ptr [ebp-468] ; Load pointer to new memory
00A356B8 50 push eax ; Push it
00A356B9 8D4D C8 lea ecx,dword ptr [ebp-38] ; Load pointer to <TEAN_KEY>
00A356BC 51 push ecx ; Push it
00A356BD E8 3E560400 call <TeanRounds> ; Call TeanRounds
00A356C2 83C4 10 add esp,10 ; Correct stack after __cdecl call
00A356C5 ^ EB AD jmp short 00A35674 ; Loop for <TEAN_LOOP_COUNT> iterations
00A356C7 6A FF push -1 ; Push more ECB Decrypt
00A356C9 8B95 84FBFFFF mov edx,dword ptr [ebp-47C] ; Load <CHUNK_SIZE>
00A356CF 52 push edx ; Push it
00A356D0 8B85 98FBFFFF mov eax,dword ptr [ebp-468] ; Load pointer to new memory
00A356D6 50 push eax ; Push it
00A356D7 8D4D C8 lea ecx,dword ptr [ebp-38] ; Load pointer to <TEAN_KEY>
00A356DA 51 push ecx ; Push it
00A356DB E8 20560400 call <TeanRounds> ; Call TeanRounds
00A356E0 83C4 10 add esp,10 ; Correct stack after __cdecl call
00A356E3 8B95 84FBFFFF mov edx,dword ptr [ebp-47C] ; Load pointer to new memory
00A356E9 8B85 90FBFFFF mov eax,dword ptr [ebp-470] ; Load <CHUNK_SIZE>
00A356EF 8D4C10 F8 lea ecx,dword ptr [eax+edx-8] ; Load pointer to second last dword in chunk
00A356F3 898D 94FBFFFF mov dword ptr [ebp-46C],ecx ; Save it
00A356F9 8D95 88FBFFFF lea edx,dword ptr [ebp-478] ; Load pointer to buffer to receive <CHECK_DWORD_1>
00A356FF 52 push edx ; Push it
00A35700 8B85 94FBFFFF mov eax,dword ptr [ebp-46C] ; Load pointer to second last dword (incremented to last dword on next call)
00A35706 50 push eax ; Push it
00A35707 E8 04EE0000 call 00A44510 ; Call wrapper around GetLong
00A3570C 83C4 08 add esp,8 ; Correct stack after __cdecl call
00A3570F 8985 94FBFFFF mov dword ptr [ebp-46C],eax ; Save new pointer
00A35715 8D8D 80FBFFFF lea ecx,dword ptr [ebp-480] ; Load pointer to buffer to receive <CHECK_DWORD_2>
00A3571B 51 push ecx ; Push it
00A3571C 8B95 94FBFFFF mov edx,dword ptr [ebp-46C] ; Load pointer to last dword
00A35722 52 push edx ; Push it
00A35723 E8 E8ED0000 call 00A44510 ; Call wrapper around GetLong
00A35728 83C4 08 add esp,8 ; Correct stack after __cdecl call
00A3572B 8985 94FBFFFF mov dword ptr [ebp-46C],eax ; Save pointer (useless now...)
00A35731 8B85 80FBFFFF mov eax,dword ptr [ebp-480] ; Load <CHECK_DWORD_2>
00A35737 F7D0 not eax ; NOT it
00A35739 3985 88FBFFFF cmp dword ptr [ebp-478],eax ; Compare it with <CHECK_DWORD_1>
00A3573F 0F85 8F120000 jnz 00A369D4 ; Skip to next certificate if not a match[/font]

The newer check incorporates the CRC32 of the reversed level 10 public parameters, if the certificate is level 10 of course, but the principle is the same. I can't honestly recall whether or not it is a null dword used with unsigned and/or ElGamal or if there is another value created/extracted.

Taken from Armadillo v9.00


02F13899 8B4D 08 mov ecx,dword ptr [ebp+8] ;Load pointer to 'key_info' struct
02F1389C 8B91 80040000 mov edx,dword ptr [ecx+480] ; Load value from 'key_info' struct
02F138A2 8995 48FAFFFF mov dword ptr [ebp-5B8],edx ; Save as <DWORD_5>

Taking a bit of a closer look at Armadillo v9.00 (RadioBoss) it would appear that they've also incorporated another shared key system, which would explain the message during protection about 'missing keyset or out of date, generating keyset'. Either way, capture the data after it is decrypted and then the algorithm is the same... I've successfully recoded it in assembler, now i will see if i can code a bruteforcer to attack this part of the key system.

If i can do it in assembler then there shouldn't be a reason not to be able to port it to C/C++ and CUDA.

HR,

Ghandi

Edited by ghandi
  • Like 4
Link to comment
Share on other sites

I've coded my own SymmetricVerify routine in ASM, C and CUDA, now i just need to throw it all away and start from scratch...

I have verified the function has worked on default certificates which i know the symmetric key for, i have yet to test it on a non-default certificate (still with a known symmetric to confirm results) but i'm confident so far that all 3 versions are functional. Now it only remains to figure out bottlenecks and make it go as fast as i possibly can.

ASM: Port to x64 and use SIMD instructions, multithreaded.

C: Port to x64?

CUDA: Hybridize the workload so that the GPU is doing RNG and MD5, then split the blocks off into portions for threads to post-process the resulting MD5 hashes.

ALL: Optimize and clean up code, possibly recode core entirely. Add older symmetric bruteforcer for faster bruteforcing, can confirm which one is valid now.

HR,

Ghandi

EDIT: You know your CUDA code is grossly inefficient when an ASM implementation of MD5 hashing is faster than the CUDA version. I really need to learn how CUDA works and how to code efficiently with it...

EDIT2: Older Armadillo is bruteforced in little to no time now: 19.374451 seconds.

Newer checksumming projects around 3 hours, i have yet to check it properly though.

Edited by ghandi
  • Like 2
Link to comment
Share on other sites

@deepzero: Check PlayClaw 2.x keygen by FFF :-) SeVeN nailed it again - PlayClaw uses VMProtect's registration scheme with RSA-2048. Don't ask me how they (he) did it :-S..

Link to comment
Share on other sites

SunBeam: I think a ton of people would want to know how they beat RSA-2048, me included....

Ghandi: now you just need OpenCL for the AMD people :P

Edited by mudlord
Link to comment
Share on other sites

indeed, pretty amazing... :S

statement from the VMP developers would be interesting.

Hell, i`d be extremely &$%$ if i spent 100 bucks on a protection system and then it gets not only cracked, but keygenned...

Link to comment
Share on other sites

Okay, playing with CUDA i've done the following:

1. Introduced multithreading on the host side.

2. Started using non-default streams for the operations, unique to each thread on the host side.

3. Launching kernels and then using cudaMemcopyAsync to use the concurrency ability of my GPU.

4. Optimized the md5 routine so that the only variable being used is the symmetric, the rest is constant.

5. Tried various thread and block configurations to find the fastest for my card.

Time is now down to 8.03 seconds for older Armadillo symmetric keys, i have problems with the newer type though which i think is nvcc unrolling automatically, i'm working on it. As for the other method i am going to add, i have no idea what results i will get so i wont bother to project anything.

HR,

Ghandi

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...