Some small reverse programs

admin 2024年1月5日00:13:13评论20 views字数 5897阅读19分39秒阅读模式

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.

Some small reverse programs
Some small reverse programs

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:
Some small reverse programs

"Too easy"

This one is rather easy. Take a look at the kernel code:
Some small reverse programs

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)

Some small reverse programs

"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.

Some small reverse programs

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:

Some small reverse programs

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:

Some small reverse programs

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))

Some small reverse programs

"CrackMe2.exe"

Run it at first and input a random string, we can see the hint as below:
Some small reverse programs
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:
Some small reverse programs

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):

Some small reverse programs

And as for detect A:

Some small reverse programs

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:

Some small reverse programs

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]))