Lab 5 - x86 Assembly Code
In this lab, you will familiarize yourself with x86 assembly code as produced by the Microsoft Visual Studio compiler from C-level source code that you write. This is in preparation for exploring malware assembly code where no high-level source code is available.
Upload the following items to the Lab 5 Assignment on Canvas when finished.
- Your source code (.h and .cpp)
- Your compiled binary (.exe)
- The PDF file containing the required documentation
Using Visual Studio, write a Windows Console Application that demonstrates the following code elements:
- For-loop that does simple arithmetic within the loop
- While-loop that does simple arithmetic within the loop
- If-else if-then control structure that assigns a variable a different value depending on the result of the branching operation
- Switch statement
- Compound if-statement (using && or ||)
__stdcallfunction call (3 arguments, 1 return value, with simple arithmetic within the function). Note: You should explicitly tell the compiler what calling convention you want to use for this function. See MSDN documentation on Argument Passing and Naming Conventions
__cdeclFunction call (3 arguments, 1 return value, with simple arithmetic within the function). Note: You should explicitly tell the compiler what calling convention you want to use for this function. See MSDN documentation on Argument Passing and Naming Conventions
- Call a Win32 API function - Note, for this code element, you only need to document the assembly code that passes arguments to the function and deals with its return value. You do not need to document the assembly code for the function itself.
Keep these elements as simple as possible, and do not nest them.
After writing your program, produce a PDF that contains — for each code element — the following items:
- The original code snippet in C
- The code snippet in x86 assembly as produced by Visual Studio. (Note: For the function calls, this must include the caller, the callee, and any stack cleanup after the function call).
- A line by line plain English explanation, in your own words, of exactly what is happening in the assembly code to implement the original C code. Your explanation should include elements that are not visible in the higher level language, such as the function call and return mechanism.
In addition, provide two screenshots in your PDF report. One screenshot should be from Visual Studio, and one from x32dbg, showing the same assembly code for a particular code element (your choice), thereby demonstrating that you know how to locate code in a binary file. Draw a box or an arrow on the screenshot so it is obvious to the reader which lines of assembly are being presented. You only need to do this for one of the code elements above, not all eight.
Note: The plain English explanation of each line of assembly code is the most important element of this lab! Be sure that you fully explain the assembly code.
Warning: Build your program in DEBUG MODE. If you build in release mode, the compiler will "helpfully" optimize and re-order the binary output, and it will be difficult to correlate your C++ code with the assembly code
You have two choices in how to view the assembly code generated by the compiler. Both approaches will show you the same assembly code, but differ in terms of ease-of-use.
Visual Studio Disassembler — Easier to read, but not realistic for malware — Visual Studio can directly show the resulting assembly code. First build your executable, and then start and immediately halt the debugger by choosing Debug->Step Into. The debugger should break immediately after entering main(). Then choose Debug->Windows->Disassembly and you should see your C/C++ code interspersed with the corresponding assembly code.
- Pros: It's very easy to find what you are looking for
- Cons: Malware executables do not include the symbol tables and original source code that would allow a disassembler to provide this level of detail. Don't get used to this level of handholding, as you will never see it again.
External Disassembler (x32dbg, IDA Pro, ...) — Harder to read, but very realistic for malware — For malware reverse engineering, you will typically use a standalone disassembler (e.g. IDA Pro) or disassembler/debugger (e.g. x32dbg/x64dbg).
- If you will be moving this executable to a different virtual machine or computer (to use the disassembler, for example), build a binary that includes the C Language Runtime. To do this, select Project->Properties->C/C++->Code Generation and change Runtime Library to "Multi-threaded Debug (/MTd)"
- If you built a 32-bit binary, use the x32dbg disassembler to view the assembly.
- If you built a 64-bit binary, use the x64dbg disassembler to view the assembly.
- Both disassemblers (x32dbg and x64dbg) are included in your Windows virtual machine image. Simple drag and drop your compiled executable onto the desired Desktop shortcut to open the tool. It will immediately disassemble your executable, enter the debugger, and pause execution.
- The significant challenge here is, without a symbol table and original source code, how do you find "your" assembly code in the midst of all of the compiler-generated initialization code? Truly a needle in a haystack situation for even a tiny program like this.
- One method is to print out a really obvious string at the first line of main() in your program. In x32dbg, you can the search for this string by right clicking and choosing Search For->All Modules->String References and entering your custom string in the search box. Then, right click on the matching line and choose Follow in Disassembler.
- Another method would be to use the Win32 API to set a breakpoint, and run the disassembler/debugger until you hit that breakpoint. Include code like this in your program at the start of main():
if (IsDebuggerPresent()) __debugbreak();
- If you want to run your code (step through it and watch the registers change), select the desired line, and then choose Debug->Run until selection.