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.