Reverse Engineering Stack Exchange is a question and answer site for researchers and developers who explore the principles of a system through analysis of its structure, function, and operation. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have this dissassembled routine from an executable but I am having troubles to translate it to C#.

.text:005C9290 ; =============== S U B R O U T I N E =======================================
.text:005C9290 ; Attributes: bp-based frame
.text:005C9290 sub_5C9290      proc near               ; CODE XREF: .text:00574256p
.text:005C9290                                         ; sub_5ACC50+68p ...
.text:005C9290 SystemTimeAsFileTime= _FILETIME ptr -8
.text:005C9290 arg_0           = dword ptr  8
.text:005C9290                 push    ebp
.text:005C9291                 mov     ebp, esp
.text:005C9293                 push    ecx
.text:005C9294                 push    ecx
.text:005C9295                 lea     eax, [ebp+SystemTimeAsFileTime]
.text:005C9298                 push    eax             ; lpSystemTimeAsFileTime
.text:005C9299                 call    ds:GetSystemTimeAsFileTime
.text:005C929F                 mov     eax, [ebp+SystemTimeAsFileTime.dwLowDateTime]
.text:005C92A2                 mov     ecx, [ebp+SystemTimeAsFileTime.dwHighDateTime]
.text:005C92A5                 push    0
.text:005C92A7                 add     eax, 2AC18000h
.text:005C92AC                 push    offset unk_989680
.text:005C92B1                 adc     ecx, 0FE624E21h
.text:005C92B7                 push    ecx
.text:005C92B8                 push    eax
.text:005C92B9                 call    sub_5D0500
.text:005C92BE                 mov     ecx, [ebp+arg_0]
.text:005C92C1                 test    ecx, ecx
.text:005C92C3                 jz      short locret_5C92C7
.text:005C92C5                 mov     [ecx], eax
.text:005C92C7 locret_5C92C7:                          ; CODE XREF: sub_5C9290+33j
.text:005C92C7                 leave
.text:005C92C8                 retn
.text:005C92C8 sub_5C9290      endp

However, I have this pseudo-code from this function generated by IDA Pro:

__int64 __cdecl sub_5C9290(int a1)
  __int64 result; // qax@1
  unsigned __int64 v2; // ST00_8@1
  struct _FILETIME SystemTimeAsFileTime; // [sp+0h] [bp-8h]@1

  HIDWORD(v2) = ((_DWORD)SystemTimeAsFileTime.dwLowDateTime >= 0xD53E8000u)
              + SystemTimeAsFileTime.dwHighDateTime
              - 27111903;
  LODWORD(v2) = SystemTimeAsFileTime.dwLowDateTime + 717324288;
  result = sub_5D0500(v2, (unsigned int)&unk_989680, 0);
  if ( a1 )
    *(_DWORD *)a1 = result;
  return result;

One problems is that code won't compile, this code doesn't make sense:

HIDWORD(v2) = ((_DWORD)SystemTimeAsFileTime.dwLowDateTime >= 0xD53E8000u)
              + SystemTimeAsFileTime.dwHighDateTime
              - 27111903;

Also one problem is the ADC command which all I can find is that it is exactly as ADD but it also adds the CARRY FLAG to the result, but I can't find any ways to reproduce this command in C#. And what about all those HIDWORD and LODWORD macros?

share|improve this question
You should consider an add followed by an adc to just be an extended (in this case, 64-bit) addition. In this particular case a 64-bit constant (0FE624E212AC18000h) is being added to a two-limb value made up of ecx:eax. – Iwillnotexist Idonotexist Sep 2 '14 at 3:13
D53E8000h is -2AC18000h. The snippet confusing you is merely the calculation of the carry value. – Iwillnotexist Idonotexist Sep 2 '14 at 3:17
up vote 2 down vote accepted

This is 64-bit math. The compiler has to do the addition in two steps because the processor can only work 32 bits at a time. And carry has to be propagated from the low addition to the high one - same way when you do addition of multiple-digit numbers on paper.

Here's what the current version of the decompiler (1.7) produces (after fixing the function prototype):

result = sub5D0500(time - 116444736000000000i64, 10000000i64);

And (just a guess) if you rename sub5D0500 to __alldiv (compiler helper function for 64-bit division), it becomes:

result = (time - 116444736000000000i64) / 10000000;

Apparently you're looking at MSVC's _time64 implementation. From time64.c:

 * Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
#define EPOCH_BIAS  116444736000000000i64
__time64_t __cdecl _time64 (
        __time64_t *timeptr
        __time64_t tim;
        FT nt_time;
        GetSystemTimeAsFileTime( &(nt_time.ft_struct) );
        tim = (__time64_t)((nt_time.ft_scalar - EPOCH_BIAS) / 10000000i64);
        if (timeptr)
                *timeptr = tim;         /* store time if requested */
        return tim;
share|improve this answer
sub5D0500 is this: So what exact am I looking at? (Pseudo: – Leandro Battochio Sep 2 '14 at 4:06

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.