Some small reverse programs
Here I'd like to share some small and simple problems in some CTF games. They are much too easy for those advanced players, so actually, this is just something could practice my English...
"Easy"
Load into the IDA and you can go to the kernel function directly, as the images below.
Since the password table is hard-coded into the program, a easy way to solve it is enter a random string, which length is 16 chars, and break on every time EIP==0x8048521
. Do not forget to modify 74 1A
to EB 1A
.
However, to let it painful, I decided to look into its algorithm and calculate out a register code.
In the picture above, s
is the location of inputed string, while var_C
is loop counter i
. FYI, sar eax, 1Fh
here is equal to shr eax, 1Fh
since eax is always a relatively small positive number.
We can write the python version of the check function:
password = [0x76,0x70,0x42,0x4A,0x51,0x5F,
0x5E,0x5D,0x40,0x41,0x54,0x53,
0x59,0x5A,0x50,0x56]
inputcode = raw_input()
if len(inputcode)!=16:
print("Error!")
exit(-1)
for i in range(len(inputcode)):
if password[i] != ord(inputcode[i]) ^ ord(inputcode[(((((i+1)>>0x1F)>>0x1C)+(i+1))&0x0F)-(((i+1)>>0x1F)>>0x1C)]):
print("Error!")
exit(-1)
print("OK!")
Then it's time to simplify this program. Since i
is not big, so the shr
will result in zero. Then the if
sentence can be changed into:
if password[i] != inputcode[i] ^ inputcode[(i+1)&0x0F]
So we can ensure that this program will treat string as a loop, and do xor between current item and next item. When those values meets, it is the right char. Apparently, just get a possible string:
password = [0x76,0x70,0x42,0x4A,0x51,0x5F,
0x5E,0x5D,0x40,0x41,0x54,0x53,
0x59,0x5A,0x50,0x56]
visiable_chars=list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*/.`~!@#$%^&()_{}[]|\\;:'\",<.>")
for init_char in visiable_chars:
code = [ [] for i in range(16) ]
flag = 1
code[0] = ord(init_char)
for i in range(15):
code[i+1] = code[i] ^ password[i]
if chr(code[i+1]) in visiable_chars:
flag = 1
else:
flag = 0
break
if flag:
if code[0]^code[15]==password[15]:
for i in range(16):
code[i]=chr(code[i])
print(str().join(code))
Here is a possible list:
0F6t>o0n3s2f5l6f
2D4v<m2l1q0d7n4d
4B2p:k4j7w6b1h2b
5C3q;j5k6v7c0i3c
6@0r8i6h5u4`3j0`
7A1s9h7i4t5a2k1a
+]-o%t+u(h)}.w-}
-[+i#r-s.n/{(q+{
*\,n$u*t)i(|/v,|
/Y)k!p/q,l-y*s)y
$R"`*{$z'g&r!x"r
(^.l&w(v+k*~-t.~
'Q!c)x'y$d%q"{!q
,Z*h"s,r/o.z)p*z
Let's test it in the real world:
"Too easy"
This one is rather easy. Take a look at the kernel code:
Just simple one-by-one xor encryption, so this one is much easier
password=[0x2A, 0x23, 0x21, 0x29, 0x27, 0x30, 0x63, 0x63, 0x25, 0x2D, 0x25, 0x2D, 0x25, 0x2D, 0x63, 0x63]
code=""
for i in password:
code=code+chr(i^0x42)
print(code)
"Keygen"
This is quite old, and same as the one I've did during summer camp. I'd like to refer to some old pics in my old report.
Obviously, just have a look at pepper()
, gaia()
, Thor()
and hades()
. And during the analysis we can see the table is dynamically generated with the following code:
Apparently that I used X-rays, since some small tricks of complier should be resolved by the machine itself. Generally, we need to find all integers ranged at 0x3E8~0x7D0 and could be mod by 20 with 3. Then we can use another diagram to show its procedure of judging register code:
Finally, time for our keygen and test:
#!/usr/bin/python
from random import randint
if __name__=="__main__":
start=randint(1000,1900)
end=2001
v=start
while v%20!=3:
v=v+1
p=2*(int(v/3)+16)
if (p<=999):
p=7*int(v/3)+42
v=str(v)
p=str(p)
q=str(randint(10,99))
print("da-%s-%sX%s-%s%s-da"%(v,p[:1:-1],p[1::-1],q,q))
"CrackMe2.exe"
Run it at first and input a random string, we can see the hint as below: Load it into IDA and nothing could be found. It's apparently since our IDA is not set to view Unicode strings as default. Press ^U in IDA-Strings, and select "Unicode", we can find that string:
Do some jobs(trace call flow) and we can see that when the function at 0x411A20 returns true, our code is right. Another way is that, since it's an GUI program, we can just find it out by checking the xref of GetDlgItemTextW()
, which exists in User32.dll. After all, we've reached 0x411A20, and saw the following code(after some modification):
And as for detect A:
So we need to ensure input[2*i]==table_419080[4*i]
and while i in range(0,0x20,2)
. Then it turns out that detect B is:
And that means for every i in range(1,0x1F,2)
has input[2*i]==table_419000[4*i]
.
Considering this program is a unicode one, we can write this python script:
table=[ 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xB1, 0x19, 0xBF, 0x44, 0x4E, 0xE6,
0x40, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]
code=[chr(0) for i in range(0,0x20)]
for i in range(0,0x20,2):
code[1*i]=chr(table[0x80+4*i])
for j in range(1,0x1F,2):
code[1*j]=chr(table[4*j])
print(str().join(code[:0x20]))