Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from struct import pack, unpack
- # the crackme is a huge mach-o executable with a nice and original obfuscation
- # I decided to study it under ollydbg by loading it with a custom loader (there is only few imports and all are standards (except the MD5 call))
- # it's ugly but it works well :) (and olly is definitively the best debugger to study obfuscated codes :) )
- '''
- #include <stdio.h>
- #include <stdlib.h>
- #include <openssl/md5.h>
- #include <windows.h>
- int main()
- {
- PBYTE maclol = VirtualAlloc(NULL, 0xB8744, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
- HANDLE hFile = CreateFileA("a.out", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
- DWORD numberOfBytesRead;
- int (*macmain)(int argc, char** argv);
- char *argv[2] = {"a.out"};
- ReadFile(hFile, maclol, 0xB8744, &numberOfBytesRead, NULL);
- maclol -= 0x1000;
- maclol[0x056C3E] = 0x68;
- *(PDWORD)(&maclol[0x056C3E+1]) = (DWORD)fread;
- maclol[0x056C3E+5] = 0xC3;
- maclol[0x056C44] = 0x68;
- *(PDWORD)(&maclol[0x056C44+1]) = (DWORD)fseek;
- maclol[0x056C44+5] = 0xC3;
- maclol[0x056C4A] = 0x68;
- *(PDWORD)(&maclol[0x056C4A+1]) = (DWORD)ftell;
- maclol[0x056C4A+5] = 0xC3;
- maclol[0x056C56] = 0x68;
- *(PDWORD)(&maclol[0x056C56+1]) = (DWORD)memcmp;
- maclol[0x056C56+5] = 0xC3;
- maclol[0x056C5C] = 0x68;
- *(PDWORD)(&maclol[0x056C5C+1]) = (DWORD)memcpy;
- maclol[0x056C5C+5] = 0xC3;
- maclol[0x056C62] = 0x68;
- *(PDWORD)(&maclol[0x056C62+1]) = (DWORD)memset;
- maclol[0x056C62+5] = 0xC3;
- maclol[0x056C68] = 0x68;
- *(PDWORD)(&maclol[0x056C68+1]) = (DWORD)printf;
- maclol[0x056C68+5] = 0xC3;
- maclol[0x056C38] = 0x68;
- *(PDWORD)(&maclol[0x056C38+1]) = (DWORD)fopen;
- maclol[0x056C38+5] = 0xC3;
- maclol[0x056BEA] = 0x68;
- *(PDWORD)(&maclol[0x056BEA+1]) = (DWORD)MD5;
- maclol[0x056BEA+5] = 0xC3;
- macmain = (int (*)(int argc, char** argv))(&maclol[0x40E40]);
- macmain(2, argv);
- return 0;
- }
- '''
- # the verification involved 4 modular polynomials equations with 4 variables :
- # the key consist of 0x2000 4-uples of polynoms (P1, P2, P3, P4)
- # C1, C2, C3 and C4 are calculated by using the following equations and must be equals to those stored in the binary :
- # C1 = P1*(x^1+x^2+x^3 [0xE]) + P2*(x^0+x^1+x^3 [0xB]) + P3*(x^0+x^2+x^3 [0xD]) + P4*(x^0+x^3 [0x9])
- # C2 = P1*(x^0+x^3 [0x9]) + P2*(x^1+x^2+x^3 [0xE]) + P3*(x^0+x^1+x^3 [0xB]) + P4*(x^0+x^2+x^3 [0xD])
- # C3 = P1*(x^0+x^2+x^3 [0xD]) + P2*(x^0+x^3 [0x9]) + P3*(x^1+x^2+x^3 [0xE]) + P4*(x^0+x^1+x^3 [0xB])
- # C4 = P1*(x^0+x^1+x^3 [0xB]) + P2*(x^0+x^2+x^3 [0xD]) + P3*(x^0+x^3 [0x9]) + P4*(x^1+x^2+x^3 [0xE])
- # I coded the basic operation on this field and
- # a little Gaussian elimination to solve those equations and so recover the 4uples P1, P2, P3 and P4.
- def mul_mod(P1, P2) :
- tmp1 = P1
- tmp2 = P2
- r = 0
- while tmp2 :
- if tmp2 & 1 :
- r ^= tmp1
- tmp2 >>= 1
- if tmp1 & 0x80000000 :
- tmp1 ^= 0x8000001B
- tmp1 <<= 1
- return r
- def mul(P1, P2) :
- tmp1 = P1
- tmp2 = P2
- r = 0
- while tmp2 :
- if tmp2 & 1 :
- r ^= tmp1
- tmp1 <<= 1
- tmp2 >>= 1
- return r
- def div(P1, P2) :
- assert P1 > P2
- i = 0
- r = 0
- m = P1
- log2P2 = 0
- while P2 >> log2P2 :
- log2P2 += 1
- log2P2 -= 1
- while P1 >= (P2 << i) :
- i += 1
- while i >= 0 :
- if m & (1 << (i + log2P2)) :
- m ^= P2 << i
- r |= 1 << i
- i -= 1
- return r, m
- def eea(u, v):
- u1 = 1
- u2 = 0
- u3 = u
- v1 = 0
- v2 = 1
- v3 = v
- while v3 != 0:
- q, t3 = div(u3, v3)
- t1 = u1 ^ mul(q, v1)
- t2 = u2 ^ mul(q, v2)
- u1 = v1
- u2 = v2
- u3 = v3
- v1 = t1
- v2 = t2
- v3 = t3
- return u1, u2, u3
- def inv(P) :
- u1, u2, u3 = eea(0x100000036, P)
- assert(u3 == 1)
- return u2
- gauss = [
- ([0, 0, 1, 0], [0xD, 0x9, 0xE, 0xB]),
- ([0, 1, 0, 0], [0x9, 0xE, 0xB, 0xD]),
- ([0, 0, 0, 1], [0xB, 0xD, 0x9, 0xE]),
- ([1, 0, 0, 0], [0xE, 0xB, 0xD, 0x9])
- ]
- for i in xrange(4) :
- invx = inv(gauss[i][1][i])
- for j in xrange(4) :
- gauss[i][0][j] = mul_mod(gauss[i][0][j], invx)
- gauss[i][1][j] = mul_mod(gauss[i][1][j], invx)
- for j in xrange(4) :
- if j != i :
- coeff = gauss[j][1][i]
- for k in xrange(4) :
- gauss[j][0][k] ^= mul_mod(coeff, gauss[i][0][k])
- gauss[j][1][k] ^= mul_mod(coeff, gauss[i][1][k])
- # table of the reference (C1, C2, C3, C4) 4-uple values checked at the end of the execution
- table = file("table", "rb").read()
- key = ""
- while table :
- out = unpack("<IIII", table[:0x10])
- table = table[0x10:]
- for i in xrange(4) :
- r = 0
- for j in xrange(4) :
- r ^= mul_mod(gauss[i][0][j], out[j])
- key += pack("<I", r)
- file("ctf-pass-file.txt", "wb").write(key)
- # by the way, there is a bug in the crackme, only the first 0x11 bytes of the 0x20 000 bytes table are checked :)
Add Comment
Please, Sign In to add comment