BuringStraw

BuringStraw

Junk_Instruction (2019 West Lake Swordsmanship Preliminary)

Problem: xctf

MFC program, use xspy to view window information.

The ID of the check button is 03e9, and the window has the function OnCommand: notifycode=0000 id=03e9,func= 0x00C72420(Junk_Instruction.exe+ 0x002420 ).

Entering this function (sub_402420), you can see a conditional statement: if ( (unsigned __int8)sub_402600(v2 + 16) ). The two branches are to pop up the correct and incorrect dialog boxes, indicating that sub_402600 is the verification function.

There are many junk instructions in this function. It first uses a call to push the return address, then pops the return address from the stack, modifies it, and pushes it back. Snap, the return address changes.

.text:0040293F E8 00 00 00 00                call    $+5
.text:0040293F
.text:00402944
.text:00402944                               loc_402944:                             ; DATA XREF: sub_402600+398↓r
.text:00402944 58                            pop     eax
.text:00402945 89 85 C4 FD FF FF             mov     [ebp+var_23C], eax
.text:0040294B E8 03 00 00 00                call    loc_402953
.text:0040294B
.text:0040294B                               ; ---------------------------------------------------------------------------
.text:00402950 EA                            db 0EAh
.text:00402951                               ; ---------------------------------------------------------------------------
.text:00402951 EB 09                         jmp     short loc_40295C
.text:00402951
.text:00402953                               ; ---------------------------------------------------------------------------
.text:00402953
.text:00402953                               loc_402953:                             ; CODE XREF: sub_402600+34B↑j
.text:00402953 5B                            pop     ebx
.text:00402954 43                            inc     ebx
.text:00402955 53                            push    ebx
.text:00402956 B8 11 11 11 11                mov     eax, 11111111h
.text:0040295B C3                            retn
.text:0040295C                               ; ---------------------------------------------------------------------------
.text:0040295C
.text:0040295C                               loc_40295C:                             ; CODE XREF: sub_402600+351↑j
.text:0040295C E8 07 00 00 00                call    loc_402968
.text:0040295C
.text:00402961 BB 33 33 33 33                mov     ebx, 33333333h
.text:00402966 EB 0D                         jmp     short loc_402975
.text:00402966
.text:00402968                               ; ---------------------------------------------------------------------------
.text:00402968
.text:00402968                               loc_402968:                             ; CODE XREF: sub_402600:loc_40295C↑p
.text:00402968 BB 11 11 11 11                mov     ebx, 11111111h
.text:0040296D 5B                            pop     ebx
.text:0040296E BB 75 29 40 00                mov     ebx, offset loc_402975
.text:00402973 53                            push    ebx
.text:00402974 C3                            retn

As a result, these junk instructions do not create a very complex branching structure. They all jump to the next segment in order, so they just need to be completely replaced with nop.

The same applies to the functions 2AF0, 2CA0, and 2e80. After removing the obfuscation, it was found that their functions are to remove the flag and parentheses and reverse them, initialize RC4, and encrypt with RC4. There is a loop below to compare the ciphertext for correctness.

The ciphertext is the long assignment starting with 2600 (5bD6D026C8DD197E6E3ECB16917DFFAFDD7664B0F7E58957829F0C009ED045FA), and the password is qwertyuiop.

Put it into CyberChef and you will get the result. Remember to reverse it. Remember to wrap it with flag{}.


PS:

At first, I didn't dare to completely replace everything with NOPs because there were assignments to eax and ebx, and I was afraid they were important. As a result, I ended up with a bunch of JMPs. IDA: 6. Later, I looked at the script to remove obfuscation written by a master and found that it directly replaced everything with NOPs... That script is for Python 2, so I modified it to Python 3 to make it work.

from ida_bytes import get_bytes, patch_bytes
import re
addr = 0x402600
end = 0x402ae3
buf = get_bytes(addr, end-addr)
def handler1(s):
    s = s.group(0)
    print("".join(["%02x"%i for i in s]))
    s = b"\x90"*len(s)
    return s
p = b"\xe8\x00\x00\x00\x00.*?\xc3.*?\xc3"
buf = re.sub(p, handler1, buf, flags=re.I)
patch_bytes(addr, buf)
print("Done")

However, this matching seems to have some problems. The function for RC4 encryption will be replaced with NOPs multiple times, so the range written above is limited to sub_402600. (If you have already guessed that it is RC4 encryption, it won't have much impact).


I thought I knew MFC, but I was completely confused. Now I know there is something called xspy.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.