*Description: ChecksumMultiGuard_MD5_unpacking.exe demonstrates that self-checksumming can occur when the locations being checksummed are not themselves executed, but are used to create code that is executed. This is the file that should be traced. ChecksumMultiGuard_MD5_packing.exe produces source that can be used to build ChecksumMultiGuard_MD5_unpacking.exe, using random permutations of operations and constants. =========================================================== *Usage: ChecksumMultiGuard_MD5_unpacking.exe *Output: The MD5 value of Abraham Lincoln's Gettysburg Address. *Usage: ChecksumMultiGuard_MD5_packing.exe *Output: unpacking.c is created; the MD5 value of Abraham Lincoln's Gettysburg Address as well, for reference. =========================================================== *Note: This program uses the same source to compute an MD5 hash as the other samples. Much of the MD5 computation takes place in the execution of the unsigned char array code_buf. code_buf is an array of hex values which, when unpacked correctly, form the executable code of the original MD5 program. Since it may seem suspicious to use source code with binary code already in it, it should be noted that code_buf can be replaced with any array of binary code. To use another program instead of the MD5 program, use an “inlined” version of it. Meaning any function calls in the source code should be directly replaced by the function’s code; in addition, any global variables should be moved into the function body. These measures are all taken to ensure there are no absolute references, so that the code produced is effectively portable. After that, convert the code to a hex string. This can be done by compiling the function’s code, then manually going through each instruction in a debugger and copying its opcode into the hex array. Similarly, the output of “objdump -d” may be used to obtain the instruction encodings. Or a simple routine can be written in the source which parses the function code from beginning to end, then produces its hex string in the appropriate format. In the samples, the MD5 code was produced from http://people.csail.mit.edu/rivest/Md5.c. The function MDString() in our source was assembled from “inlining” the original source code into one function. Then code_buf was produced as mentioned above, from parsing MDString() from beginning to end using C labels. =========================================================== *ChecksumMultiGuard_MD5_unpacking algorithm: In the case of ChecksumMultiGuard_MD5_unpacking, each byte in code_buf has had a series of 100 (i.e. NUM_LAYERS (from packing.c)) layers of encryption applied. code_buf is passed to unpack(). An int unpacked_checksum_layerX exists for each layer X of unpacking, which is the precalculated checksum produced from adding all of the bytes within a given layer. For each layer, a for loop iterates through the buffer and applies a single decryption operation (either an add, subtract, or xor). In every other layer of decryption, a checksum is taken by calling checksum(). checksum() adds up every byte in a layer X, compares it with unpacked_checksum_layerX, then determines whether a tamper has occurred via printing to stdout. After unpacking, execution is passed back to main(), where code_buf is casted to a function pointer then called. *ChecksumMultiGuard_MD5_packing algorithm: ChecksumMultiGuard_MD5_packing produces an unpacking.c that can be used to build ChecksumMultiGuard_MD5_unpacking. It performs this by passing a program’s code_buf (in this case, for an MD5 program) to pack(), along with a file pointer to the future unpacking.c file. In pack(), there are two main parts: encryption, and file printing. For the encryption, a random operation (i.e. add, subtract, or xor) and a random operator are applied to every byte of code_buf 100 (i.e. NUM_LAYERS) times. The file printing produces a special line that should be noted. The resulting fully encrypted buffer is printed as “unsigned char code_unpacking_layer%d[ARR_LENGTH] = ”, and should then be copied back into multilevel-unpacking.c code_buf; if this isn’t done, ChecksumMultiGuard_MD5_unpacking will not compile because of a line in unpacking.c reminding you to do this.