Resurrecting SCD

When I became interested in reverse engineering all the way back in 2000, the first Win32 disassembler I stumbled across was simply called “Win32 Program Disassembler” authored by one Sang Cho. I took to calling it ‘scd’ for Sang Cho’s Disassembler. The original program versions and source code are still available for download. I remember being able to compile v0.23 of the source code with gcc under Unix; 0.25 is no go due to extensive reliance on the Win32 development environment.

I recently wanted to use scd again but had some trouble compiling. As was the case the first time I tried compiling the source code a decade ago, it’s necessary to transform line endings from DOS -> Unix using ‘dos2unix’ (I see that this has been renamed to/replaced by ‘fromdos’ on Ubuntu).

Beyond this, it seems that there are some C constructs that used to be valid but are now rejected by gcc. The first looks like this:

return  (int) c = *(PBYTE)((int)lpFile + vCodeOffset);

Ahem, “error: lvalue required as left operand of assignment”. Removing the “(int)” before the ‘c’ makes the problem go away. It’s a strange way to write a return statement in general. However, ‘c’ is a global variable that is apparently part of some YACC/BISON-type output.

The second issue is when a case-switch block has a default label but with no code inside. Current gcc doesn’t like that. It’s necessary to at least provide a break statement after the default label.

Finally, the program turns out to not be 64-bit safe. It is necessary to compile it in 32-bit mode (compile and link with the ‘-m32’ flag or build on a 32-bit system). The static 32-bit binary should run fine under a 64-bit kernel.

Alternatively: What are some other Win32 disassemblers that work under Linux?

7 thoughts on “Resurrecting SCD

  1. SvdB

    I wonder whether whoever wrote that code actually meant what they wrote.
    The cast binds stronger than the assignment, so this is interpreted as
    return ((int) c) = *(PBYTE)((int)lpFile + vCodeOffset);
    not
    return (int) (c = *(PBYTE)((int)lpFile + vCodeOffset));

    Casting an lvalue is rightfully rejected. After all, what does it mean if you assign a value to a char which you casted to int?

    If the intent is to reinterpret the address where ‘c’ points to as a pointer to an integer, then the correct way to write this would be ‘*((int *) &c) = …’.
    If I’m not mistaken, this is how the piece of code which you quoted would be interpreted on old gcc versions. This also means that removing that ‘(int)’ cast makes it do something other than what it originally did.

    If the original writer just intended to cast the result of the assignment to an int, then the parentheses were wrong to begin with.

    Also, if you do not need an interactive disassembler (and IDA does indeed work fine under Wine), there’s always objdump.
    You can compile binutils with ‘–enable-targets=all’ (and possibly –enable-64-bit-bfd) to add support for many other platforms and executable formats, including Windows PE.

  2. Reimar

    Short and simple version of above objdump suggestion: Install the mingw toolchain and you’ll get an objdump that can handle Windows binaries.

Comments are closed.