Debug Fundamentals Exercise 2: Some reverse engineering for Thanksgiving

Debug Fundamentals Exercise 2: Some reverse engineering for Thanksgiving

  • Comments 42


Continuing our series on “Fundamentals Exercises”, we have some more reverse engineering for you!  Again, these exercises are designed more as learning experiences rather than simply puzzlers.  We hope you find them interesting and educational!  Feel free to post your responses here, but we won’t put them on the site until after we post the “official” responses, to avoid spoilers.


Examine the following code, registers, and stack values to determine the following:


1.       What is the return value from DemoFunction2?

2.       What is the purpose of DemoFunction2?

3.       Bonus: Both the last exercise and this week’s exercise involved accessing data at ebp+8.  Why ebp+8?



1.       You probably don’t want to manually walk through every instruction that executes in the loop.  Instead, walk through a few iterations to determine the intent of the code.

2.       The bracket notation [] in the assembly means to treat the value in brackets as a memory address, and access the value at that address.

3.       32-bit integer return values are stored in eax



0:000> uf 010024d0


010024d0 55              push    ebp

010024d1 8bec            mov     ebp,esp

010024d3 8b5508          mov     edx,dword ptr [ebp+8]

010024d6 33c0            xor     eax,eax

010024d8 b920000000      mov     ecx,20h

010024dd d1ea            shr     edx,1

010024df 7301            jnc     asmdemo2!DemoFunction2+0x12 (010024e2)

010024e1 40              inc     eax

010024e2 e2f9            loop    asmdemo2!DemoFunction2+0xd (010024dd)

010024e4 5d              pop     ebp

010024e5 c3              ret


0:000> r

eax=80002418 ebx=7ffd7000 ecx=00682295 edx=00000000 esi=80002418 edi=00000002

eip=010024d0 esp=0006fe98 ebp=0006fea8 iopl=0         nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246


010024d0 55              push    ebp


0:000> dps esp

0006fe98  0100251c asmdemo2!main+0x20

0006fe9c  80002418

0006fea0  00000002

0006fea4  00000000

0006fea8  0006ff88

0006feac  01002969 asmdemo2!_mainCRTStartup+0x12c

0006feb0  00000002

0006feb4  00682270

0006feb8  006822b8

0006febc  f395c17d

0006fec0  00000000

0006fec4  00000000

0006fec8  7ffd7000

0006fecc  00000000

0006fed0  00000000

0006fed4  00000000

0006fed8  00000094

0006fedc  00000006

0006fee0  00000000

0006fee4  00001771

0006fee8  00000002

0006feec  76726553

0006fef0  20656369

0006fef4  6b636150

0006fef8  00003120

0006fefc  00000000

0006ff00  00000000

0006ff04  00000000

0006ff08  00000000

0006ff0c  00000000

0006ff10  00000000

0006ff14  00000000


[Update: our answer. Posted 12/04/2008]

We had a great response to this exercise!  It was good to see so many of you going through this.  There were some readers that found this a good exercise for beginners, and others were looking for a return to Puzzlers.  As an FYI, we may do more Puzzlers in the future, but for now we are going to continue on the “Fundamentals Exercise” track to help all our readers build up a solid foundation for debugging.


It was interesting to read how several of you not only gave the answers, but made suggestions for how the code could be optimized!  I want to point out that the code we post for these exercises isn’t intended to be the optimal solution; it is written as a learning tool.   That said, keep that in-depth feedback coming; I think everyone will benefit from a discussion of optimization.


Answers to exercise 2:


  1. DemoFunction2 returns 5, which is the number of bits set in 80002418, the value at ebp+8.
  2. DemoFunction2 finds the hamming weight of the 32-bit value passed to the function (it returns the count of bits that are equal to 1).
  3. ebp points to the base of the stack frame (the value stored there points to the previous frame's ebp), ebp+4 points to the return address, and ebp+8 points to the first parameter passed to the function.  Note that the value of ebp changes in the function prolog, at instruction 010024d1.  At this point ebp is set to 0006fe94, so at instruction 010024d3, ebp+8 is 0006fe9c, and [ebp+8] = 80002418.
Leave a Comment
  • Please add 2 and 3 and type the answer here:
  • Post
  • 1. The return value is 1

    2. The function calculates number of set bits in dword that is sent as a parameter.

    3. Not sure but:

    ebp+0 - return address

    ebp+4 - this

    ebp+8 - the parameter

  • 1) Returned value is 5

    2) It is counting the number of 1 bit in the passed in 80002418h parameter value.

  • The return value will be 0x5.

    This function is returning number of 1's in the given input's binary representation.

    ebp+8 is the first parameter passed to this function.

  • What is the return value from DemoFunction2

    It seems to be 5

     What is the purpose of DemoFunction2? : No idea ?

    Why ebp+8? : It contains the first parameter to function...

    Anways, it was fun. Keep posting.

  • #1) 5

    #2) PopCount (Binary Counter)

    #3) Paramater #1 after stack frame is setup

    Finally, Same code written in assembly

    popcount FRAME dwValue

    mov ecx,[dwValue]

    mov eax,ecx

    shr eax,1

    and eax,055555555h

    sub ecx,eax

    mov eax,ecx

    shr eax,2

    and ecx,033333333h

    and eax,033333333h

    add ecx,eax

    mov eax,ecx

    shr eax,4

    add eax,ecx

    and eax,00F0F0F0Fh

    mov ecx,eax

    shr ecx,8

    add eax,ecx

    mov ecx,eax

    shr ecx,16

    add eax,ecx

    and eax,00000003Fh




    DemoFunction2 takes paramter one, a 32 bit paramater, and then continually shifts it 32 times (20h), each time it is shifted the carry flag is checked to see if the shifted bit was set, if it wasn't the final result isn't incremented, if it was, the final result is incremented,, surmising that if each bit causes an increment to the return value the function simply counts the bits of the first paramater passed to our function.

    PopCount does the same thing but as if the value needed folded upon itself, take every other bit and add them, then take every two bits and add them, then take every four bits and add them together, all the way until you add 16 bits to 16 bits. The reason for the subtraction instead of addition on first call is the reduction of overflow without the need for anding.

  • OK ... here is my try.

    I think the code snippet is for counting how many 0 bits in the given 32bit unsigned number. The pesudo-C++ code would be like:

    UINT DemoFunctions(UINT x)


       UINT nRet = 0;

       for (int i = 0; i < 32; ++i)


           if (x&1 == 0)

               nRet ++;

           x = x >> 1;


       return nRet;


    From the raw call stack the parameter is [0006fe9c] = 80002418, so the answer should be 27.

  • 5

    ret = count of non zero bits

  • 1. CountBitsSetInDword(DWORD dwData = 80002418) = 5

    3. ebp is the value of esp, ebp+4 is the return ip, ebp+8 is the first parameter of the function.

  • It appears that the function counts the number of bits that are set to 1 in the argument passed to the function.

    In this example, the argument 80002418 is passed in and I expect the function would return a value of 5 because there are 5 bits set in the argumnet.

  • Oops - it is ebp+8 (not ebp+4).

    The function counts the number of bits set in the ebp+8 location.  ebp+8 contains a 00000002 which means EAX should have a 1 in it upon completion of the function.

    I incorrectly looked at 80002418 as the routine argument (which is at ebp+4).

    Mike R

  • 1. The return value from DemoFunction2 is 5.

    2. The function's purpose is to count up the number of bits in the function's first parameter.

    3. The data at ebp+8 is always where a function's first parameter is as long as the function was compiled to have a stack frame set up.

    That was pretty fun! :-)


  • 1. return 5.

    2. return the number of 1 bit in arg.

Page 3 of 3 (42 items) 123