home *** CD-ROM | disk | FTP | other *** search
/ Hacks & Cracks / Hacks_and_Cracks.iso / hackersclub / km / library / cracking / fravia-taskman1.txt < prev    next >
Text File  |  1998-03-25  |  32KB  |  647 lines

  1. How To Disassemble A Windows Program
  2.  
  3.      I think this small exercise (shamelessly abducted from Schulman's book
  4.      -> see here) could be very helpful for all the future crackers trying
  5.      to get some bearings during their difficult disassembly of Windows
  6.      programs.
  7.  
  8.      One of the problems in reverse engineering, is that nobody teaches you
  9.      how to do it, and you have mostly to learn alone the relevant
  10.      techniques, loosing an enormous amount of time.
  11.  
  12.      Disassembling Windows with a reverse engineering approach is *very*
  13.      useful for actual cracking purposes, and it's time to form a new
  14.      generation of Windows crackers, since the ghastly Microsoft domination
  15.      will not easily be crushed without many more good crackers to help us.
  16.      What +ORC writes and teaches in his lessons is fundamental, but
  17.      unfortunately he does not teach the "elementary" side of cracking
  18.      Windows (for DOS cracking, on the contrary, the Crackbook of Uncle Joe
  19.      is a good primer for beginners and intermediate alike), so I'll try to
  20.      help here to form a strong generation of little strong crackers... as
  21.      +ORC wrote to me: "we are all throwing seeds in the air, some of them
  22.      will land astray, but some of them will grow".
  23.  
  24.      Remember that cracking Windows is *very* different, in approach and in
  25.      techniques, from cracking DOS. The older ones (that I unconditionally
  26.      respect) do not seem to grab it totally... they are probably so
  27.      experienced that they can use more or less the same techniques in
  28.      cracking all OSs... but in my (humble) opinion, that's not necessarily
  29.      the best approach... you see, cracking Windows is "puzzle solving",
  30.      cracking DOS is "playing chess"... you'll understand what I mean if
  31.      you read what follows.
  32.  
  33.      Please do excuse my shortcomings both in the techniques I teach (I am
  34.      an autodidact) and in the language I use.
  35.  
  36.      If at any time you feel you should need more references, check the
  37.      Windows 3.1. SDK Programmer's Reference, Volume 1: Overview, Chapter
  38.      22, Windows Application Startup.
  39.  
  40.      A little knowledge of the C language is required in order to
  41.      understand a part of the following (you better understand it right
  42.      now: the only existing programming language is C, most applications
  43.      are written in C, "real" programmers use C... you may dislike it, but
  44.      that's the reality, so you better get a little knowledge of C
  45.      programming as soon as you can, if you want to crack more
  46.      effectively... you'll find enough C tutorials on the net). This said,
  47.      most of the following can be used even if you do not know C.
  48.  
  49. Disassembling Taskman
  50.  
  51.      As example for this introduction, I have chosen Taskman.exe, the small
  52.      program you'll find inside your C:\WINDOWS directory... you can invoke
  53.      it anytime typing CTRL+ESC in Windows 3.1.
  54.  
  55.      I have done it because Schulman has already (very well) worked on it,
  56.      and therefore he spares me a lot of work, and also because I agree
  57.      totally with him in his choice: Taskman it's a very good example for
  58.      all newbys to Windows cracking. Actually it's a pity that you cannot
  59.      (yet) find Schulman's books on the net... I believe they should be
  60.      indisputably there! (Anybody with a good scanner reading this?).
  61.  
  62.      Let's start from the beginning... by looking at TASKMAN's startup
  63.      code. Taskman is a very small win 3.1 program, but it's rich in
  64.      surprises, as you'll see. After you disassembly taskman.exe with WCB
  65.      (see below) and *after* you have printed the listing, you may use the
  66.      "Loader" utility to pop out inside winice at the beginning of Taskman:
  67.  
  68.      start:
  69.      1FBF:4B9 33ED              XOR     BP,BP     ;begins
  70.      1FBF:4BB 55                PUSH    BP        ;save BP
  71.      1FBF:4BC 9A8D262701        CALL    KERNEL!INITTASK
  72.      ...
  73.  
  74.      So we are set for snooping around "live", but first (and that's very
  75.      important for Windows programs) we have to prepare a good disassembled
  76.      listing of our target. You see, in DOS such a work does not make much
  77.      sense, because the disassembled listing would not differ much from
  78.      what you get on screen through softice, but in Windows, on the
  79.      contrary, we can get quite a lot more out of all the information that
  80.      is already present inside our target. The following explains this
  81.      point:
  82.  
  83.      You can use any good disassembler (like Winsourcer, from V
  84.      communication, a good version, cracked by the ubiquitous Marquis de
  85.      Soiree, is available on the web) but i'll use the disassembled listing
  86.      of WCB (Windows CodeBack -> download version 1.5. from my "tools"
  87.      page: here).
  88.  
  89.      WCB is a very good Win 3.1. disassembler, created by the ungarian
  90.      codemaster Leslie Pusztai (pusztail@tigris.klte.hu), and, in my modest
  91.      opinion, it's far better than sourcer. If you use it, remember that it
  92.      works from DOS: the main rule is to create first of all the *.EXL
  93.      files for the necessary "mysterious" *.dll with the command:
  94.  
  95.      wcb -x [mysterious.dll]and you'll be able, afterwards, to disassemble
  96.      the *.exe that called them.
  97.  
  98.      But all this is not necessary for humble Taskman.exe, where we get
  99.      following header information: Filename: TASKMAN.EXE Type: Segmented
  100.      executable Module description: Windows Task Manager 3.1 Module name:
  101.      TASKMAN Imported modules:
  102.  
  103.      Filename:            TASKMAN.EXE
  104.      Type:                Segmented executable
  105.      Module description:  Windows Task Manager 3.1
  106.      Module name:         TASKMAN
  107.  
  108.      Imported modules:
  109.        1: KERNEL
  110.        2: USER
  111.  
  112.      Exported names by location:
  113.        1:007B     1 TASKMANDLGPROC
  114.  
  115.      Program entry point:   1:04B9
  116.      WinMain:               1:03AE
  117.  
  118.      and we can get straight the entry point code:
  119.        1.04B9                           ;  Program_entry_point
  120.        1.04B9 >33ED                     xor     bp, bp
  121.        1.04BB  55                       push    bp
  122.        1.04BC  9AFFFF0000               call    KERNEL.INITTASK
  123.        1.04C1  0BC0                     or      ax, ax
  124.        1.04C3  744E                     je      0513
  125.        1.04C5  81C10001                 add     cx, 0100
  126.        1.04C9  7248                     jb      0513
  127.        1.04CB  890E3000                 mov     [0030], cx
  128.        1.04CF  89363200                 mov     [0032], si
  129.        1.04D3  893E3400                 mov     [0034], di
  130.        1.04D7  891E3600                 mov     [0036], bx
  131.        1.04DB  8C063800                 mov     [0038], es
  132.        1.04DF  89163A00                 mov     [003A], dx
  133.        1.04E3  33C0                     xor     ax, ax
  134.        1.04E5  50                       push    ax
  135.        1.04E6  9AFFFF0000               call    KERNEL.WAITEVENT
  136.        1.04EB  FF363400                 push    word ptr [0034]
  137.        1.04EF  9AFFFF0000               call    USER.INITAPP
  138.        1.04F4  0BC0                     or      ax, ax
  139.        1.04F6  741B                     je      0513
  140.        1.04F8  FF363400                 push    word ptr [0034]
  141.        1.04FC  FF363200                 push    word ptr [0032]
  142.        1.0500  FF363800                 push    word ptr [0038]
  143.        1.0504  FF363600                 push    word ptr [0036]
  144.        1.0508  FF363A00                 push    word ptr [003A]
  145.        1.050C  E89FFE                   call    WinMain
  146.        1.050F  50                       push    ax
  147.        1.0510  E890FF                   call    04A3
  148.  
  149.      This is similar to the standard startup code that you'll find in
  150.      nearly *every* Windows program. It calls three functions: InitTask(),
  151.      WaitEvent(), and InitApp().
  152.  
  153.      We know jolly well about InitTask(), but let's imagine that we would
  154.      have here a more mysterious routine than these, and that we would like
  155.      to know what for items are hold in the CX, SI etc. register on return
  156.      from InitTask() without disassembling everything everywhere... how
  157.      should we proceed?
  158.  
  159.      First of all let's see if the locations [0030] - [003A] are used
  160.      elsewhere in our program... this is typical when you work with
  161.      disassembled listings: to find out what one block of code means, you
  162.      need most of the time to look first at some other block of code. Let's
  163.      see.. well, yes! Most of the locations are used again a few lines down
  164.      (1.04F8 to 1.0508).
  165.  
  166.      Five words are being pushed on the stack as parameters to WinMain().
  167.      If only we knew what those enigmatic parameter were... but wait: we do
  168.      actually know what those parameters are! WinMain(), the function being
  169.      called from this code, always looks like:
  170.  
  171.      int  PASCAL WinMain(WORD hInstance, WORD hPrevInstance,
  172.           LPSTR lpCmdLine, int nCmdShow);
  173.  
  174.      And we (should) know that in the Pascal calling convention, which is
  175.      used extensively in Windows because it produces smaller code than the
  176.      cdecl calling convention, arguments are pushed on the stack in the
  177.      same order as they appear inside the function declaration. That's a
  178.      good news for all little crackers!
  179.  
  180.      Thus, in our example, [0034] must be hInstance, [0032] must be
  181.      hPrevinstance, [0038]:[0036] are segment and offset of lpcmdline and
  182.      [003A] must be nCmdshow.
  183.  
  184.      What makes this important is that we can now go and replace *every*
  185.      occurrence of [0034] by a more useful name such as hInstance, every
  186.      occurrence of [0032] by hPrevInstance and so on. This clarify not just
  187.      this section of the listing, but every section of the listing that
  188.      refers to these variables. Such global substitutions of useful names
  189.      for placeholder names or addresses is indispensable when working with
  190.      a disassembled listing. After applying these changes to the fragment
  191.      shown earlier, we end up with something more understandable:
  192.  
  193.        1.04CB  890E3000                 mov     [0030], cx
  194.        1.04CF  89363200                 mov     hPrevInstance, si
  195.        1.04D3  893E3400                 mov     hInstance, di
  196.        1.04D7  891E3600                 mov     lpCmdLine+2, bx
  197.        1.04DB  8C063800                 mov     lpCmdLine, es
  198.        1.04DF  89163A00                 mov     nCmdShow, dx
  199.        1.04E3  33C0                     xor     ax, ax
  200.  
  201.        1.04E5  50                       push    ax
  202.        1.04E6  9AFFFF0000               call    KERNEL.WAITEVENT
  203.        1.04EB  FF363400                 push    word ptr hInstance
  204.        1.04EF  9AFFFF0000               call    USER.INITAPP
  205.        1.04F4  0BC0                     or      ax, ax
  206.        1.04F6  741B                     je      0513
  207.        1.04F8  FF363400                 push    word ptr hInstance
  208.        1.04FC  FF363200                 push    word ptr hPrevInstance
  209.        1.0500  FF363800                 push    word ptr lpCmdLine
  210.        1.0504  FF363600                 push    word ptr lpCmdLine+2
  211.        1.0508  FF363A00                 push    word ptr nCmdShow
  212.        1.050C  E89FFE                   call    WinMain
  213.  
  214.      Thus if we didn't already know what InitTask() returns in various
  215.      register (our Taskman here is only an example for your later work on
  216.      much more mysterious target programs), we could find it out right now,
  217.      by working backwards from the parameters to WinMain(). Windows
  218.      disassembling (and cracking) is like puzzle solving: the more little
  219.      pieces fall into place, the more you get the global picture. Trying to
  220.      disassemble Windows programs without this aid would be unhealthy: you
  221.      would soon delve inside *hundreds* of irrelevant calls, only because
  222.      you did not do your disassemble homework in the first place.
  223.  
  224.      It was useful to look at the startup code because it illustrated the
  225.      general principle of trying to substitute useful names such as
  226.      hPrevInstance for useless labels such as [0034]. But, generally, the
  227.      first place we'll look examining a Windows program is WinMain(). Here
  228.      the code from WCB:
  229.  
  230.        1.03AE                           ;  WinMain
  231.        1.03AE >55                       push    bp
  232.        1.03AF  8BEC                     mov     bp, sp
  233.        1.03B1  83EC12                   sub     sp, 0012
  234.        1.03B4  57                       push    di
  235.        1.03B5  56                       push    si
  236.        1.03B6  2BFF                     sub     di, di
  237.        1.03B8  397E0A                   cmp     [bp+0A], di
  238.        1.03BB  7405                     je      03C2
  239.        1.03BD  2BC0                     sub     ax, ax
  240.        1.03BF  E9CC00                   jmp     048E
  241.  
  242.        1.03C2 >C47606                   les     si, [bp+06]
  243.        1.03C5  26803C00                 cmp     byte ptr es:[si], 00
  244.        1.03C9  7453                     je      041E
  245.        1.03CB  897EF2                   mov     [bp-0E], di
  246.        1.03CE  EB1E                     jmp     03EE
  247.  
  248.        1.03D0 >26803C20                 cmp     byte ptr es:[si], 20
  249.        1.03D4  741E                     je      03F4
  250.        1.03D6  B80A00                   mov     ax, 000A
  251.        1.03D9  F72E1000                 imul    word ptr [0010]
  252.        1.03DD  A31000                   mov     [0010], ax
  253.        1.03E0  8BDE                     mov     bx, si
  254.        1.03E2  46                       inc     si
  255.        1.03E3  268A07                   mov     al, byte ptr es:[bx]
  256.        1.03E6  98                       cbw
  257.        1.03E7  2D3000                   sub     ax, 0030
  258.        1.03EA  01061000                 add     [0010], ax
  259.  
  260.        1.03EE >26803C00                 cmp     byte ptr es:[si], 00
  261.        1.03F2  75DC                     jne     03D0
  262.  
  263.        1.03F4 >26803C00                 cmp     byte ptr es:[si], 00
  264.        1.03F8  741B                     je      0415
  265.        1.03FA  46                       inc     si
  266.        1.03FB  EB18                     jmp     0415
  267.  
  268.        1.03FD >B80A00                   mov     ax, 000A
  269.        1.0400  F72E1200                 imul    word ptr [0012]
  270.        1.0404  A31200                   mov     [0012], ax
  271.        1.0407  8BDE                     mov     bx, si
  272.        1.0409  46                       inc     si
  273.        1.040A  268A07                   mov     al, byte ptr es:[bx]
  274.        1.040D  98                       cbw
  275.        1.040E  2D3000                   sub     ax, 0030
  276.        1.0411  01061200                 add     [0012], ax
  277.  
  278.        1.0415 >26803C00                 cmp     byte ptr es:[si], 00
  279.        1.0419  75E2                     jne     03FD
  280.        1.041B  8B7EF2                   mov     di, [bp-0E]
  281.  
  282.        1.041E >6A29                     push    0029
  283.  
  284.        1.0420  9AF9000000               call    USER.GETSYSTEMMETRICS
  285.        1.0425  50                       push    ax
  286.        1.0426  1E                       push    ds
  287.        1.0427  681600                   push    0016
  288.        1.042A  9AFFFF0000               call    KERNEL.GETPROCADDRESS
  289.        1.042F  8946F4                   mov     [bp-0C], ax
  290.        1.0432  8956F6                   mov     [bp-0A], dx
  291.        1.0435  0BD0                     or      dx, ax
  292.        1.0437  7407                     je      0440
  293.        1.0439  6A01                     push    0001
  294.        1.043B  6A01                     push    0001
  295.        1.043D  FF5EF4                   call    far ptr [bp-0C]
  296.  
  297.        1.0440 >68FFFF                   push    selector 1:0000
  298.        1.0443  687B00                   push    007B
  299.        1.0446  FF760C                   push    word ptr [bp+0C]
  300.        1.0449  9AFFFF0000               call   KERNEL.MAKEPROCINSTANCE
  301.        1.044E  8BF0                     mov     si, ax
  302.        1.0450  8956FA                   mov     [bp-06], dx
  303.        1.0453  0BD0                     or      dx, ax
  304.        1.0455  7426                     je      047D
  305.        1.0457  FF760C                   push    word ptr [bp+0C]
  306.        1.045A  6A00                     push    0000
  307.        1.045C  6A0A                     push    000A
  308.        1.045E  6A00                     push    0000
  309.        1.0460  8B46FA                   mov     ax, [bp-06]
  310.        1.0463  50                       push    ax
  311.        1.0464  56                       push    si
  312.        1.0465  8976EE                   mov     [bp-12], si
  313.        1.0468  8946F0                   mov     [bp-10], ax
  314.        1.046B  9AFFFF0000               call    USER.DIALOGBOX
  315.        1.0470  8BF8                     mov     di, ax
  316.        1.0472  FF76F0                   push    word ptr [bp-10]
  317.        1.0475  FF76EE                   push    word ptr [bp-12]
  318.        1.0478  9AFFFF0000               call   KERNEL.FREEPROCINSTANCE
  319.  
  320.        1.047D >8B46F6                   mov     ax, [bp-0A]
  321.        1.0480  0B46F4                   or      ax, [bp-0C]
  322.        1.0483  7407                     je      048C
  323.        1.0485  6A01                     push    0001
  324.        1.0487  6A00                     push    0000
  325.        1.0489  FF5EF4                   call    far ptr [bp-0C]
  326.  
  327.        1.048C >8BC7                     mov     ax, di
  328.  
  329.        1.048E >5E                       pop     si
  330.        1.048F  5F                       pop     di
  331.        1.0490  8BE5                     mov     sp, bp
  332.        1.0492  5D                       pop     bp
  333.        1.0493  C20A00                   ret     000A
  334.  
  335.      Let's begin from the last line: ret 000A. In the Pascal calling
  336.      convention, the callee is responsible for clearing its arguments off
  337.      the stack; this explains the RET A return. In this particular case,
  338.      WinMain() is being invoked with a NEAR call. As we saw in the startup
  339.      code, with the Pascal calling convention, arguments are pushed in
  340.      "forward" order. Thus, from the prospective of the called function,
  341.      the last argument always has the *lowest* positive offset from BP
  342.      (BP+6 in a FAR call and BP+4 in a NEAR call, assuming the standard
  343.      PUSH BP -> MOV BP,SP function prologue, like at the beginning of this
  344.      WinMain().
  345.  
  346.      Now write the following in your cracking notes (the ones you really
  347.      keep on your desk when you work... close to your cocktail glass):
  348.      function parameters have *positive* offsets from BP, local variables
  349.      have *negative* offsets from BP.
  350.  
  351.      What does all this mean... I hear some among you screaming... well, in
  352.      the case of WinMain(), and in a small-model program like Taskman,
  353.      which starts from BP+4, you'll have:
  354.  
  355.      int  PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
  356.           LPSTR lpCmdLine, int nCmdShow);
  357.      nCmdShow       =         word ptr [bp+4]
  358.      lpCmdLine      =         dword ptr [bp+6]
  359.      hPrevInstance  =         word ptr [bp+0Ah]
  360.      hInstance      =         word ptr [bp+0Ch]
  361.  
  362.      Yeah... let's rewrite it:
  363.  
  364.        1.03B6  2BFF                 sub     di, di
  365.        1.03B8  397E0A               cmp     hPrevInstance, di
  366.        1.03BB  7405                 je      03C2
  367.        1.03BD  2BC0                 sub     ax, ax
  368.        1.03BF  E9CC00               jmp     048E
  369.  
  370.        1.03C2 >C47606               les     si, dword ptr lpCmdLine
  371.        1.03C5  26803C00             cmp     byte ptr es:[si], 00
  372.  
  373.      We can now see, for example, that WinMain() checks if hPrevInstance is
  374.      zero (sub di,di); if it isn't, it immediately jump to the pops and
  375.      exits (jmp 048E).
  376.  
  377.      Look at the code of WinMain() once more... notice that our good
  378.      Taskman appears to be inspecting its command line... funny: the
  379.      Windows documentation says nothing about command line arguments to
  380.      Taskman... Look around location 1.03D0 above, you'll see that Taskman
  381.      appears to be looking for a space (20h), getting a character from the
  382.      command line, multiplying it by 10 (0Ah), subtracting the character
  383.      zero (30h) and doing other things that seem to indicate that it's
  384.      looking for one or more *numbers*. The code line 1.03E7 SUB ax,30h
  385.      it's a typical code line inside many routines checking for numbers.
  386.      The hex ascii code for numbers is 30 for 0 to 39 for 9, therefore the
  387.      transmutation of an ascii code in hex *number* is pretty easy: mov al,
  388.      your_number and sub ax,30... you'll find it very often.
  389.  
  390.      Rather than delve further into the code, it next makes sense to *run*
  391.      taskman, feeding it different numbers on the command line, and seeing
  392.      what it does (it's surprising how few crackers think of actually going
  393.      in and *running* a program before spending much time looking at its
  394.      code).
  395.  
  396.      Normally Taskman runs when you type CTRL+ESC in Windows, but its just
  397.      a regular program, that can be run with a command line, like any other
  398.      program.
  399.  
  400.      Indeed, running "TASKMAN 1" behaves differently from just running
  401.      "TASKMAN": it positions the Task List in the upper-left corner of the
  402.      screen, instead of in the middle. "TASKMAN 666 666" (the number of the
  403.      beast?) seems to position it in the lower right corner.
  404.  
  405.      Basically, the command line numeric arguments seem to represent an
  406.      (x,y) position for our target, to override its default position in the
  407.      middle of the screen.
  408.  
  409.      So you see, there are hidden 'goodies' and hidden 'secrets' even
  410.      behind really trivial little programs like Taskman (and believe me:
  411.      being able to identify this command line checking will be very useful
  412.      ;-) when you'll crack applications and/or games that *always* have
  413.      backdoors and hidden goodies).
  414.  
  415.      Back to the code (sip your favourite cocktail during your
  416.      scrutinies... may I suggest a Traitor? -> see the legendary FraVia's
  417.      cocktail page here) you can see that the variables [0010] and [0012]
  418.      are being manipulated. What are these for?
  419.  
  420.      The answer is *not* to stare good and hard at this code until it makes
  421.      sense, but to leave this area and see how the variables are used
  422.      elsewhere in the program... maybe the code elsewhere will be easier to
  423.      understand (for bigger applications you could in this case use a
  424.      Winice breakpoint on memory range, but we'll remain with our WCB
  425.      disassembly listing).
  426.  
  427.      In fact, if we search for data [0010] and [0012] we find them used as
  428.      arguments to a Windows API function:
  429.  
  430.        1.018B >A31200           mov     [0012], ax
  431.        1.018E  FF760E           push    word ptr [bp+0E]
  432.        1.0191  FF361000         push    word ptr [0010]
  433.        1.0195  50               push    ax
  434.        1.0196  56               push    si
  435.        1.0197  57               push    di
  436.        1.0198  6A00             push    0000
  437.        1.019A  9AFFFF0000       call    USER.MOVEWINDOW
  438.  
  439.      This shows us *immediately* what [0010] and [0012] are. MoveWindows()
  440.      is a documented function, whose prototype is:
  441.  
  442.      void FAR PASCAL MoveWindow(HWND hwnd, int nLeft, int nTop,
  443.                                 int nWidth, int nHeight, BOOL fRepaint);
  444.  
  445.        1.018B >A31200          mov     [0012], ax
  446.        1.018E  FF760E          push    word ptr [bp+0E]  ;hwnd
  447.        1.0191  FF361000        push    word ptr [0010]   ;nLeft
  448.        1.0195  50              push    ax                ;nTop
  449.        1.0196  56              push    si                ;nWidth
  450.        1.0197  57              push    di                ;nHeight
  451.        1.0198  6A00            push    0000              ;fRepaint
  452.        1.019A  9AFFFF0000      call    USER.MOVEWINDOW
  453.  
  454.      In other words, [0010] has to be nLeft and [0012] (whose contents have
  455.      been set from AX) has to be nTop.
  456.  
  457.      Now you'll do another global "search and replace" on your WCB
  458.      disassembly, changing every [0010] in the program (not just the one
  459.      here) to nLeft, and every [0012] to nTop.
  460.  
  461.      A lot of Windows cracking is this easy: all Windows programs seem to
  462.      do is call API functions, most of these functions are documented and
  463.      you can use the documentation to label all arguments to the function.
  464.      You then transfer these labels upward to other, possibly quite distant
  465.      parts of the program.
  466.  
  467.      In the case of nLeft [0010] and nTop [0012], suddenly the code in
  468.      WinMain() makes much more sense:
  469.  
  470.        1.03C2 >C47606      les     si, dword ptr lpCmdLine
  471.        1.03C5  26803C00    cmp     byte ptr es:[si], 00 ; no cmd line?
  472.        1.03C9  7453        je      041E                 ; go elsewhere
  473.        1.03CB  897EF2      mov     [bp-0E], di
  474.        1.03CE  EB1E        jmp     03EE
  475.  
  476.        1.03D0 >26803C20    cmp     byte ptr es:[si], 20 ; if space
  477.        1.03D4  741E        je      03F4                 ; go elsewhere
  478.  
  479.        1.03D6  B80A00      mov     ax, 000A
  480.        1.03D9  F72E1000    imul    nLeft                ; nleft *= 10
  481.        1.03DD  A31000      mov     nLeft, ax
  482.        1.03E0  8BDE        mov     bx, si
  483.        1.03E2  46          inc     si
  484.        1.03E3  268A07      mov     al, es:[bx]
  485.        1.03E6  98          cbw                          ; ax = char
  486.        1.03E7  2D3000      sub     ax, 0030             ; ax='0' (char-> number)
  487.        1.03EA  01061000    add     nLeft, ax            ; nleft += number
  488.  
  489.        1.03EE >26803C00    cmp     byte ptr es:[si], 00 ; NotEndOfString
  490.        1.03F2  75DC        jne     03D0                 ; next char
  491.        ...
  492.  
  493.      In essence, Taskman is performing the following operation here:
  494.  
  495.         static int nLeft, nTop;
  496.           //...
  497.           if (*lpCmdLine !=0)
  498.           sscanf(lpCmdLine, "%u %u, &nLeft, &nTop);
  499.  
  500.      Should you want 3.1. Taskman to appear in the upper left of your
  501.      screen, you could place the following line in the [boot] section of
  502.      SYSTEM.INI:
  503.  
  504.      taskman.exe=taskman.exe 1 1
  505.  
  506.      In addition, doubleclicking anywhere on the Windows desktop will bring
  507.      up Taskman with the (x,y) coordinates for the double click passed to
  508.      Taskman on its command line.
  509.  
  510.      The USER!WM_SYSCOMMAND handler is responsible for invoking Taskman,
  511.      via WinExec() whenever you press CTRL+ESC or double click the desktop.
  512.  
  513.      What else is going on in WinMain()? Let's look at the following block
  514.      of code:
  515.  
  516.        1.041E >6A29         push    0029
  517.        1.0420  9AF9000000   call    USER.GETSYSTEMMETRICS
  518.        1.0425  50           push    ax
  519.        1.0426  1E           push    ds
  520.        1.0427  681600       push    0016
  521.        1.042A  9AFFFF0000   call    KERNEL.GETPROCADDRESS
  522.        1.042F  8946F4       mov     [bp-0C], ax
  523.        1.0432  8956F6       mov     [bp-0A], dx
  524.        1.0435  0BD0         or      dx, ax
  525.        1.0437  7407         je      0440
  526.        1.0439  6A01         push    0001
  527.        1.043B  6A01         push    0001
  528.        1.043D  FF5EF4       call    far ptr [bp-0C] ; *1 entry
  529.  
  530.      The lines push 29h & CALL GETSYSTEMMETRICS are simply the assembly
  531.      language form of GetSystemMetrics(0x29). 0x29 turns out to be
  532.      SM_PENWINDOWS (look in WINDOWS.H for SM_).
  533.  
  534.      Thus, we now have GetSystemMetrics(SM_PENWINDOWS). If we read the
  535.      documentation, it says that this returns a handle to the Pen Windows
  536.      DLL if Pen Windows is installed. Remember that 16-bit return values
  537.      *always* appear in the AX register.
  538.  
  539.      Next we can see that AX, which must be either 0 or a Pen Window module
  540.      handle, is pushed on the stack, along with ds:16h.
  541.  
  542.      Let's immediately look at the data segment, offset 16h:
  543.  
  544.      2.0010  0000000000005265  db  00,00,00,00,00,00,52,65 ; ......Re
  545.      2.0018  6769737465725065  db  67,69,73,74,65,72,50,65 ; gisterPe
  546.      2.0020  6E41707000000000  db  6E,41,70,70,00,00,00,00 ; nApp....
  547.  
  548.      Therefore:
  549.  
  550.      2.0016  db 'RegisterPenApp',0
  551.  
  552.      Thus, here is what we have so far:
  553.  
  554.      GetProcAddress(
  555.           GetSystemMetrics(SM_PENWINDOWS),
  556.           "RegisterPenApp")
  557.  
  558.      GetProcAddress() returns a 4 bytes far function pointer (or NULL) in
  559.      DX:AX. In the code from WinMain() we can see this being moved into the
  560.      DWORD at [bp+0Ch] (this is 16-bit code, so moving a 32-bit value
  561.      requires two operations).
  562.  
  563.      It would be nice to know what the DWORD at [bp-0Ch] is. But, hey! We
  564.      *do* know it already: it's a copy of the return value from
  565.      GetProcAddress(GetSystemMetrics(SM_PENWINDOWS), "RegisterPenApp)! In
  566.      other words, is a far pointer to the RegisterPenApp() function, or
  567.      NULL if Pen Windows is not installed. We can now replace all
  568.      references to [bp-0Ch] with references to something like
  569.      fpRegisterPenApp.
  570.  
  571.      Remember another advantage of this "dead" Windows disassembling
  572.      vis-a-vis of the Winice approach "on live": here you can choose,
  573.      picking *meaningful* references for your search and replace
  574.      operations, like "mingling_bastard_value" or "hidden_and_-
  575.      forbidden_door". The final disassembled code may become a work of art
  576.      and inspiration if the cracker is good! (My disassemblies are
  577.      beautiful works of poetry and irony). Besides, *written*
  578.      investigations will remain documented for your next cracking session,
  579.      whereby with winice, if you do not write everything down immediately,
  580.      you loose lots of your past work (it's incredible how much place and
  581.      importance retains paper in our informatic lives).
  582.  
  583.      After our search and replaces, this is what we get for this last block
  584.      of code:
  585.  
  586.      FARPROC fpRegisterPenAPP;
  587.      fpRegisterPenApp = GetProcAddress(
  588.           GetSystemMetrics(SM_PENWINDOWS),
  589.           "RegisterPenApp");
  590.  
  591.      Next we see [or dx, ax] being used to test the GetProcAddress() return
  592.      value for NULL. If non-NULL, the code twice pushes 1 on the stack
  593.      (note the PUSH IMMEDIATE here... Windows applications only run on
  594.      80386 or higher processors... there is no need to place the value in a
  595.      register first and then push that register) and then calls through the
  596.      fpRegisterPenApp function pointer: 1.0435 0BD0 or dx, ax 1.0437 7407
  597.      je 0440 1.0439 6A01 push 0001 1.043B 6A01 push 0001 1.043D FF5EF4 call
  598.      dword ptr fpRegisterPenApp
  599.  
  600.      1.0435  0BD0         or      dx, ax
  601.      1.0437  7407         je      0440
  602.      1.0439  6A01         push    0001
  603.      1.043B  6A01         push    0001
  604.      1.043D  FF5EF4       call    dword ptr fpRegisterPenApp
  605.  
  606.      Let's have a look at the Pen Windows SDK doucmentation (and PENWIN.H):
  607.  
  608.           #define RPA_DEFAULT
  609.      void FAR PASCAL RegisterPenApp(UINT wFlags, BOOL fRegister);
  610.  
  611.      We can continue in this way with all of WinMain(). When we are done,
  612.      the 100 lines of assembly language for WinMain() boild own to the
  613.      following 35 lines of C code:
  614.  
  615.      // nLeft, nTop used in calls to MoveWindow() in TaskManDlgProc()
  616.       static WORD nLeft=0, nTop=0;
  617.         BOOL FAR PASCAL TaskManDlgProc(HWND hWndDlg, UINT msg, WPARAM
  618.          wParam, LPARAM lParam);
  619.         int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
  620.          LPSTR lpCmdLine, int nCmdShow)
  621.       {
  622.        void (FAR PASCAL *RegisterPenApp) (UINT,BOOL);
  623.        FARPROC fpDlgProc;
  624.        if (hPrevhInstance != 0)
  625.           return 0;
  626.        if (*lpCmdLine !=0 )
  627.           _fsscanf(lpCmdLine, "%u %u, &nLeft, &nTop); // pseudocode
  628.       RegisterPenApp = GetProcAddress(GetSystemMetrics(SM_PENWINDOWS),
  629.        "RegisterPenApp");
  630.       if (RegisterPenApp != 0)
  631.           (*RegisterPenApp) (RPA_DEFAULT, TRUE);
  632.       if (fpDlgProc = MakeProchInstance(TaskManDlgProc, hInstance))
  633.        {
  634.           DialogBox(hInstance, MAKEINTRESOURCE(10), 0, fpDlgProc);
  635.           FreeProcHInstance(fpDlgProc);
  636.        }
  637.       if (RegisterPenApp != 0)
  638.           (*RegisterPenApp) (RPA_DEFAULT, FALSE);
  639.         return 0;
  640.       }
  641.  
  642.      In this lesson we had a look at WinMain()... pretty interesting, isn't
  643.      it? We are not done with TASKMAN yet, though... we'll see in the next
  644.      lesson wich windows and dialog procedures TASKMAN calls. (-> lesson 2)
  645.  
  646.                                                                      FraVia
  647.