Debug Fundamentals Exercise 2: Some reverse engineering for Thanksgiving

 

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?

 

Hints:

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

asmdemo2!DemoFunction2:

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

asmdemo2!DemoFunction2:

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.