Reverse Engineering Signatus.exe (bmdyy) - Part 1
I am currently enrolled on OSED Course, I am taking a chance to practice more my reverse engineering skills and exploit development and bmddy wrote a program called Signatus and I will do a write up of my approach on reverse engineering the program. Please check Reverse Engineering Signatus.exe (bmdyy) - Part 2 if you already checked Part1.
If you have already read 1st part and 2nd part, the full poc I developed can be looked at my github Signatus.exe (bmdyy) - Exploit Dev POC
My approach was first finding entry points to feed input data where I can interact with the software and tracing the code with IDA Free (static analysis) and Windbg (Dynamic analysis). By executing the program we can see its listening on port 9999 (TCP).

I like to write a small piece of python code to send a dummy packet and with the windbg debugger attached with a breakpoint on ws2_32!recv function.
import socket
import sys
def main():
if len(sys.argv) != 2:
print("Usage: %s <ip_address>\n" % (sys.argv[0]))
sys.exit(1)
server = sys.argv[1]
port = 9999
buf = bytearray[0x41]*0x100
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server,port))
s.send(buf)
s.close()
if __name__ == '__main__':
main()
How do I know the software uses ws2_32!recv function to consume the data ?
You can load Signatus.exe on IDA Free and look for the imported functions (Imports’s tab in IDA)

Attaching the debugger and set a breakpoint on WS2_32!recv (bp WS2_32!recv) and sending a dummy packet with the python script above.
We can see that the program checks if data was received successfully after the WS2_32!recv function returned by comparing the return value in eax with 0FFFFFFFFh (-1 in decimal). We can see the comparison below at the address: 60AE135C. We passed the check, the next check it compares the return value with hard coded value of 0x4, also showing below.
Because the return value is equal to 0x4, we do not follow the successful branch (green), we follow the (red) arrow. The next branch is the one of my interest as it contains the functionality that will deny or allow us to utilize further functionality in the software. Understanding this piece is crucial to allow us to go down the correct path for the vulnerability.

There are two import point to understand the 0x60AE1399 (call ds:_time64) will get current timestamp in number of seconds elapsed since midnight (00:00:00), January 1, 1970 _time64. The result of _time64 will be passed as argument to a function at 0x60AE13A8 (I renamed this funtcion as: encrypt_timing_func). This function encrypt_timing_func will receive as first argument the _time64 and second argument 0x0.
Looking inside the encrypt_timing_func function this piece of code will perform arithmetic against the value generated by _time64 function. We see hardcoded 0xa (ecx) and 0x0 (eax) is used as well as part of division.

The value returned from the function discussed is used after the function is returned in the multiplication, left shit and xor instructions below. The result is stored in edx and compared with edi, the edi contains the first 4 bytes of our payload. If edx and edi matches, it will take (true condition) green arrow. If the value in edi (first 4 bytes of our payload) doesn’t match, the program will end and continue to listen for new incoming packets (input).

Here we can understand that the first 4 bytes of our payload need to be equal to the value in edx which contains the value transformed through _time64 by encrypt_timing_func function (0x60AE13A8) and extra aritchmetic calculation after function is returned starting at (0x60AE13AD).
I wrote a function in python that will generate the correct value for the first 4 bytes of our payload.
Recommendation.: Run your poc script in the same machine where signatus.exe is stored or you will need to sync the time between signatus.exe machine and the remote machine, any time delay the poc won’t work.
Below is the piece of encrypt_timing_func function I wrote in python. I will continue the reverse engineering in Reverse Engineering Signatus.exe (bmdyy) - Part 2 where I will continue the reverse engineering to discover the memory corruption vulnerability.
def reverse_timing(timing):
ecx = 0xa # Hard coded 0xa
eax = 0x0 # Hard coded 0x0
# xor edx, edx
edx = 0
# div ecx
edx = (eax % ecx) # Store the remainder in edx
eax = int(eax / ecx) # we div, we use int because of floating number
# mov ebx, eax
ebx = eax
# Timing
eax = int(timing) # Timing in eax
# div ecx
edx = (eax % ecx) # Store the remainder in edx
eax = int(eax/ecx) # we div, we use int because of floating number
# mov edx, ebx
edx = ebx
# dec edi
edi = 0
edi = edi-1 & 0xFFFFFFFF
# movzx esi, al
esi = eax & 0xFF
# mov eax, esi
eax = esi
# imul eax, esi
eax = (eax * esi)
# mov ecx, eax
ecx = eax
# imul ecx, esi
ecx = (eax*esi)
# mov edx, ecx
edx = ecx
# imul ecx, esi
ecx = (ecx*esi)
# and edx, 0FFFFFF00h
edx = (edx & 0x0FFFFFF00)
# shl edx, 4
edx = edx << 4
# or edx, eax
edx = (edx | eax)
# and edx, 0x0FFFFFFF0h
edx = (edx & 0x0FFFFFFF0)
# and ecx, 0FFFFF000h
ecx = (ecx & 0x0FFFFF000)
# shl ecx, 8
ecx = (ecx << 8) & 0xFFFFFFFF
# or edx, ecx
edx = (edx | ecx) & 0xFFFFFFFF
# shl edx, 4
edx = (edx << 4) & 0xFFFFFFFF
# or edx, esi
edx = (edx | esi) & 0xFFFFFFFF
# xor edx, 74829726h
edx = edx ^ 0x74829726
return edx