Introduction To Win95 Cracking

Introduction to Win95 Cracking

  A few words before beginning

    Giving credits, where credit is due ! So, i'd like to give a really BIG
    thanks to ED!SON of United Cracking Force for his tutorial about
    Windows 95 cracking, without it i won't be here telling you how to
    crack a program under win 95.
    Giving ALL the credits... all i learned about cracking is with the help
    of great tutorials : 5 Minutes 4 a Crack /NeverOne, Amateur Crackist
    Tutorial /Specular Vision, Cracking for Masses /FraVia, Old Red Cracker
    Tutorials /+ORC (A Must), The Ancient Art Of Cracking & Cracking 101
    /Buckaroo Banzai, The Cracking Manual /Cyborg, The Uncle Joe CrackBook
    /Uncle Joe (heh, what did you expect ?). But also with 40 Hex
    Magazines, The Crypt Newsletters, Virus Laboratories And Distribution.
    Note : a lot of the explaination i'll give you in Introduction parts
    are ripped from some tutorials upper, it's because i wanted to have
    something complete you can start with. Tnx again to those who wrot'em.

    For this tutorial you'll need :
    ACDSee32 V2.0 Beta
    Soft-Ice 3.00
    HexWorkShop

  Introduction to Cracking

    You might be wondering what type of programming skills you need to
    become a cracker. Knowing a higher level language such as Basic,
    Pascal, or C++ will help you somewhat in that you will have an
    understanding of what's involved in the process of writing a program
    and how certain aspects of a program function. If you don't have any
    programming skills, you have a long road ahead of you. But even if you
    can program in a high level language, in order to crack you have to
    know assembly... It really doesn't matter what language a program was
    written in in order to crack it, because all programs do the same
    thing. And that is issue commands to the microprocessor. And all
    programs when broken down to their simplest form are nothing more than
    a collection of 80XXX instructions and program specific data. This is
    the level of assembly language. In assembly you have total control of
    the system. This is also the level that the debugger operates at.

    You don't have to become a master at assembly to crack a program, but
    it helps. You do need to learn some rudimentary principles, and you
    absolutely have to become familiar with the registers of the cpu and
    how the 8088 instruction set uses them. There is no way around this.
    How proficient you are at assembly will determine how good of a cracker
    you become. You can get by on learning a few basic instructions, how to
    use a debugger, and one or two simple techniques. This will allow you
    to remove a few shareware nag screens, and maybe you'll luck out and
    remove the copy protection from a game or two, but that's it.

    You can then dynamically interact with the program and run it one line
    of code at a time, and see exactly what the program is doing in real
    time as each line of code is executed. You will also be able to
    re-assemble instructions (in memory only), edit the contents of memory
    locations, manipulate the cpu's registers, and see the effects your
    modifications have on the program as it's running. This is also where
    all your system crashes will occur... There is a lot of trial and error
    involved in cracking.

    As you get better, you'll have to write programs that will implement
    your patches if you decide to distribute them. The patches themselves
    don't have to be written in assembly.

    The sources code I included in this manual are extremely simple.
    They're written in assembly because that's the only language I know how
    to program in, but if you are already proficient in a higher level
    language, it should be trivial for you to duplicate it's methods in
    your preferred language.

  Quick Introduction To Soft-Ice 3.0

    Okay, okay, i already heard you : Hey exact, you've ripped the ED!SON
    introduction. Yes, i've taken it ;) Why should i do something if
    someone already did ? So for all of you that didn't have the chance to
    have that intro, i've a little remixed it, and here it is...

    Cracking a Windows program is most often more simple than a program
    running in Dos. In Windows, it's hard to hide anything from anyone who
    really looks for information, as long as Windows own functions are
    used. The first (and often only) tool you need is Soft-Ice, a powerfull
    debugger from NuMega (http://www.numega.com). Some people find it hard
    to use, but i will tell you how to do efficient debugging with it.

    To use Sice, you must load it before windows, to do that, just add the
    "Drive:\Path\WINICE.EXE" at the end of your "AUTOEXEC.BAT". Normally,
    the Sice Setup should have already done it. I advise you to make a
    multi-config in that way, you can load Sice only when you need it.

    Example of multi-config :
    ;--- Config.sys
    [menu]
    menuitem SICE,Load Soft-Ice Debugger Behind Windows
    menuitem NORM,Normal Mode
    menudefault NORM,5
    [SICE]
    [NORM]
    [common]
    DEVICE=C:\WIN96\HIMEM.SYS
    DOS=HIGH
    DEVICE=C:\cd\drivers\MTMCDAI.SYS /D:MTMIDE01
    FILES=40
    ;--- EOF Config.sys

    ;--- Autoexec.bat
    @ECHO OFF
    SET BLASTER=A220 I5 D1 H5 P330 T6
    SET MIDI=SYNTH:1 MAP:E
    SET PATH=C:\WIN96;C:\WIN96\COMMAND;C:\DOS;D:\NC
    SET TEMP=C:\TEMP
    SET SOUND=C:\VIBRA16
    C:\VIBRA16\DIAGNOSE /S
    C:\VIBRA16\MIXERSET /P /Q
    PROMPT $p$g
    goto %config%
    :SICE
    C:\Progra~1\SoftIc~1\WINICE.EXE
    goto common
    :NORM
    goto common
    :common
    ;--- EOF Autoexec.bat

    In the config.sys the [menu] indicates that's a multiconfig, it will
    display the two menuitem and wait for the user to select. When
    selected, the part of the config file refering to it is runned and
    followed by the [common] one. In the autoexec.bat there's a %config%
    variable set to the user'selection and is used to select witch part of
    your bat you will execute.

    So, udpate your system files if they need so, and reboot your machine.
    If you don't understand why these config files look like this, refer to
    the MS-DOS Help (Type HELP at the dos prompt).

    Now that Sice is loaded into memory, press "CTRL-D" to to pop it up.
    Here is a little description of the windows you can see on Sice screen
    :

      +----------------------+-------------------------------------------+
      | CPU Registers Window | "WR" En/Disable, "R", "Alt-R" Edit.       |
      +----------------------+-------------------------------------------+
      | FPU Registers Window | "WF" En/Disable.                          |
      +----------------------+-------------------------------------------+
      |    Locals Windows    | "WL" En/Disable, "Alt-L" Focus.           |
      +----------------------+-------------------------------------------+
      |     Watch Window     | "WW" En/Disable, "Alt-W" Focus.           |
      +----------------------+-------------------------------------------+
      |     Data Window      | "WD" En/Disable, "E", "Alt-D" to Edit.    |
      +----------------------+-------------------------------------------+
      |     Code Window      | "WC" En/Disable, "A" Edit, "Alt-C" Focus. |
      +----------------------+-------------------------------------------+
      |    Command Window    | Type Commands and read output here.       |
      +----------------------+-------------------------------------------+
      |      Help Line       | Get summary help on what you are typing.  |
      +----------------------+-------------------------------------------+

    The register window contains the general purpose and flags registers of
    the cpu. You will notice that the general purpose registers contain
    hexadecimal values. These values are just what happened to be in there
    when you brought up the debugger. You will also notice that some of the
    flags are highlighted while some are not. The highlighted flags are the
    ones that are SET. While the ones that are not highlighted are CLEARED.
    Generally, the register are also highlighted when they change value.
    From this window you will be able to manipulate the contents of the
    cpu's registers. You will change the values of the registers while
    debugging a program in order to change the behavior of the running
    program. Say you come across a JNZ instruction (jump if not zero), that
    instruction makes the decision on whether or not to make the jump based
    on the state of the (Z)ero flag. You can modify the condition of the
    (Z)ero flag in order to alter the flow of the programs code. By the
    same token, you can modify the general purpose registers in the same
    manner. Say the AX register contains 0000, and the program bases it's
    actions on that value, modifying the AX register to contain a new value
    will also have the effect of modifing the flow of the code. After you
    become comfortable with using Sice you'll begin to appreciate just how
    powerful this window is, and you'll aslo discover soon enough just how
    totally it can screw your system if you fuck up.

    The data window will display data as it exists in memory. From this
    window you can usually display, search, edit, fill, and clear entire
    ranges of memory. The two most common commands for this window are
    display and edit. The search command is also useful in cracking. Sice
    offers you 4 data windows, you can toggle from one to another using the
    "data" command. You can also change the type of data this window is
    displaying using the "format" command. You can scroll into the data
    window using ALT and arrows or PgUp/PgDn keys.

    The code window is the window in which you will interact with the
    running program. This is the most complex window, and it is where the
    bulk of debugging occurs. The layout of the window is pretty simple,
    the group of 12 numbers with the colon in the middle of them to the far
    left of the window is the address:offset of that line of code. Each
    line of code in this window is an instruction that the program will
    issue to the microprocessor, and the parameters for that instruction.
    The registers that contain the address for the current instruction
    waiting to be executed are the CS:EIP registers (code segment and
    instruction pointer). This line is highlighted, if you havent it in the
    code window use the "." command to retrieve it. You will also notice a
    group of hex numbers to the right of the addresses, this group of
    numbers is the hexadecimal equivalent of the mnemonic instructions. The
    next group of words and numbers to the right of the hex numbers are the
    mnemonic instructions themselves. You can scroll into the code window
    using ALT and arrows or PgUp/PgDn keys.

    For most examples, we'll only need to have the CPU Registers Window,
    the Data and the code one. Disable others. I'm in 60 lines mode. So if
    all windows are disabled to have the same screen as me do (comment are
    preceded by a semi-colon) :

          +--------------------+-------------------------------------+
          | :lines 60          | ; Set 60 lines mode                 |
          +--------------------+-------------------------------------+
          | :color f a 4f 1f e | ; Set psychedelic colors (Optional) |
          +--------------------+-------------------------------------+
          | :wd 22             | ; Enable Data Window 22 lines long  |
          +--------------------+-------------------------------------+
          | :wc 25             | ; Enable Code Window 25 lines long  |
          +--------------------+-------------------------------------+
          | :wr                | ; Enable Register Window            |
          +--------------------+-------------------------------------+
          | :code on           | ; Display instruction bytes         |
          +--------------------+-------------------------------------+

    This can seems you strange to have to type all these commands each time
    you'll start Sice. In fact, all these command can be done in the
    winice.dat file (in your sice directory). Let'see what is in mine :

  +-----------------------------------------------+--------------------------+
  | ;--- Example of Winice.dat                    |                          |
  +-----------------------------------------------+--------------------------+
  | ; General Variables                           |                          |
  +-----------------------------------------------+--------------------------+
  | NMI=ON                                        |                          |
  +-----------------------------------------------+--------------------------+
  | SIWVIDRANGE=ON                                |                          |
  +-----------------------------------------------+--------------------------+
  | LOWERCASE=OFF                                 | ; Disable lowercase      |
  |                                               | assembly                 |
  +-----------------------------------------------+--------------------------+
  | MOUSE=ON                                      | ; Enable mouse           |
  +-----------------------------------------------+--------------------------+
  | NOLEDS=OFF                                    | ; Disable led switching  |
  +-----------------------------------------------+--------------------------+
  | NOPAGE=OFF                                    |                          |
  +-----------------------------------------------+--------------------------+
  | PENTIUM=ON                                    | ; Pentium Op-Codes       |
  +-----------------------------------------------+--------------------------+
  | THREADP=ON                                    | ; Following Thread       |
  |                                               | Process                  |
  +-----------------------------------------------+--------------------------+
  | VERBOSE=ON                                    |                          |
  +-----------------------------------------------+--------------------------+
  | PHYSMB=16                                     | ; Exact Memory Size      |
  +-----------------------------------------------+--------------------------+
  | SYM=256                                       | ; Memoy allocated to     |
  |                                               | symbols                  |
  +-----------------------------------------------+--------------------------+
  | HST=16                                        | ; Memory allocated to    |
  |                                               | history                  |
  +-----------------------------------------------+--------------------------+
  | TRA=92                                        | ; Memory allocated to    |
  |                                               | back trace buffer        |
  +-----------------------------------------------+--------------------------+
  | ; Startup sequence                            |                          |
  +-----------------------------------------------+--------------------------+
  | INIT="lines 60;color f a 4f 1f e;wd 22;wc     |                          |
  | 22;wr;code on;x;"                             |                          |
  +-----------------------------------------------+--------------------------+
  | ; Function Keys                               |                          |
  +-----------------------------------------------+--------------------------+
  | F5="^G;"                                      | ; Run (CTRL-D)           |
  +-----------------------------------------------+--------------------------+
  | F8="^T;"                                      | ; Step into functions    |
  |                                               | (Trace)                  |
  +-----------------------------------------------+--------------------------+
  | F10="^P;"                                     | ; Step Over functions    |
  |                                               | (Procedure)              |
  +-----------------------------------------------+--------------------------+
  | F11="^G @SS:ESP;"                             | ; Step out of function   |
  +-----------------------------------------------+--------------------------+
  | ; Export Symbols                              |                          |
  +-----------------------------------------------+--------------------------+
  | EXP=c:\win96\system\kernel32.dll              |                          |
  +-----------------------------------------------+--------------------------+
  | EXP=c:\win96\system\user32.dll                |                          |
  +-----------------------------------------------+--------------------------+
  | EXP=c:\win96\system\gdi32.dll                 |                          |
  +-----------------------------------------------+--------------------------+
  | ;--- EOF Winice.dat                           |                          |
  +-----------------------------------------------+--------------------------+

    Okay, i think, it speaks by itself. Just a little note for defining
    function keys, all commands preceded by ^ are invisible, and all those
    followed by a ; are executed (the ; indicates an ENTER). Dont forget to
    load the Export Symbols !

  Cracking ACDSee 32 V2.0 Beta

  Loading ACDSee32.exe into Soft-Ice And Breaking At The Right Point.
    Run the Symbol Loader, do "File/Open Module" or you can also click on
    the first button on the left of the tool bar and browse until you can
    select the file ACDSee32.exe. Now, to start debugging you must to do
    "Module/Loads..." or click the "Load button" (next to the "Open" one).
    Perhaps Sice poped-up, saying Break Due To Load Module, or something
    like that, leave it by pressing "CTRL-D" or typing "X" followed by
    "ENTER". You should disable the "Break At WinMain Option" to dont
    pop-up Sice each time you load a module (the little lamp button).

    OK, let's go. In ACDSee, click on "Tools/Register..." Fill up the boxes
    with what you want. (I've filled them with Name:"Out Rage Pirates" and
    Registration:"112233445566"). Generally programs must read the content
    of the boxes with one of these functions :

              +----------------+----------------------------------+
              | 16-bit         | 32-bit                           |
              +----------------+----------------------------------+
              | GetWindowText  | GetWindowTextA, GetWindowTextW   |
              +----------------+----------------------------------+
              | GetDlgItemText | GetDlgItemTextA, GetDlgItemTextW |
              +----------------+----------------------------------+

    The last letter of the 32 functions tells if the function uses one-byte
    or double-byte strings. Double-byte code is RARE. So, now we gonna
    enter Sice pressing CTRL-D and set breakpoints on the getting content
    of edit boxes :

:bpx GetWindowText
:bpx GetWindowTexta
:bpx GetWindowTextw
:bpx GetDlgItemText
:bpx GetDlgItemTexta
:bpx GetDlgItemTextw

    Oki, there's no need to set BPs (BreakPointS) 0 and 3 since we know it
    is a 32-bit application, but i've put them here to be exhaustive. If
    you encounter problems settings these breakpoints, make sure that the
    export symbols are loaded in Soft-Ice : edit the file winice.dat and
    check if the semi-colons are removed from the exp= that follows the
    "Example of export symbols that can be included for chicago" near the
    end of file. Generally, you only need to keep kernel32.dll, user32.dll,
    gdi32.dll. If you get an error message "No LDT", make sure you dont run
    any other DOS application in the background,

    It's not sure that Sice will pop-up, and not all program are calling
    these Windows functions.
    Continue the program ("CTRL-D"), and click the OK button. It worked,
    we're back to Sice ! press "CTRL-D" to continue the process, back to
    Sice again ! re-re-press "CTRL-D", no more Sice pop-up. Normal, there's
    only two textboxes... Click OK to get back to the registration window.
    And now, let's throw an eye into Sice, CTRL-D. There's comments for the
    two break points :

Break due to BPX USER32!GetDlgItemTextA (ET=4.70 seconds)
Break due to BPX USER32!GetDlgItemTextA (ET=269.77 microseconds)

    It's BP 04 let's delete other BPs :

:bl                                ; BPs list
00) BPX USER!GetWindowText
01) BPX USER32!GetWindowTexta
02) BPX USER32!CharNextExW
03) BPX USER!GetDlgItemText
04) BPX USER32!GetDlgItemTextA
05) BPX USER32!AppendMenuW
:bc 0 1 2 3 5                      ; Clear BPs #0, 1, 2, 3 and 5.

    We'll do it again. Press "CTRL-D" to leave Soft-Ice, and click the OK
    button. Magic, we're back in it... Let's do a little focus : where are
    we, and what's the hell now ? We are at the start of the "Get Dialog
    Item Text A" function, and we are going to find where it is called.
    Since we know that when we do a far call to something the next logical
    instruction address is stored on the stack, we gonna set a BP on that
    address and execute the program until we reach it. G command will
    continue the program at the current CS:EIP, and set a temporary BP to
    the address indexed (@) in SS:ESP. There's a function key that
    automatically do it, normally, it's F11.

:G @SS:ESP

  Finding Where The Registation Code Is Checked

    Ok, we are back into Sice at the instruction following the call to
    DlgItemTextA. We gonna take a look on what's happenning before and
    after. Use CTRL-UP and CTRL-DOWN to move into the code window. If you
    dont have the code window on your screen you can make it appears by
    typing WC (WC 20 will set the code windows to be 20 lines long). You
    should see something like following (i've added blank lines and
    comments for clarity and future explainations) :

; Get The Name Into Buffer (ESP+8)
 0040367B 8D442418       LEA EAX, [ESP + 18]       ; Buffer(For Name) Address
 0040367F 6A1E           PUSH 0000001E             ; Max String Size
 00403681 8BB42408010000 MOV ESI, [ESP + 00000108]
 00403688 50             PUSH EAX                  ; Buffer Address
 00403689 6A6B           PUSH 0000006B             ; Control ID
 0040368B 8B3D94DA4900   MOV EDI,[USER32!GetDlgItemTextA]
 00403691 56             PUSH ESI                  ; Dialog Handle
 00403692 FFD7           CALL EDI                  ; Call GetDlgItemTextA

; Get The Registration Code Into Buffer (ESP+38)
>00403694 8D442438       LEA  EAX, [ESP + 38]      ; Buffer(Registration) Addy
 00403698 68C8000000     PUSH 000000C8             ; Max String Size
 0040369D 50             PUSH  EAX                 ; Buffer Address
 0040369E 6882000000     PUSH  00000082            ; Control ID
 004036A3 56             PUSH  ESI                 ; Dialog Handle
 004036A4 FFD7           CALL  EDI                 ; Call GetDlgItemTextA

; Registration Checking
>004036A6 8D442438       LEA  EAX, [ESP + 38]      ; Registration Buffer
 004036AA 8D4C2418       LEA  ECX, [ESP + 18]      ; Name Buffer
 004036AE 50             PUSH EAX                  ; Save Datas
 004036AF 51             PUSH ECX
!004036B0 E80BF9FFFF     CALL 00402FC0             ; Registration Check
 004036B5 83C408         ADD  ESP, 00000008        ; Free Stack
 004036B8 85C0           TEST EAX, EAX
 004036BA 7E6E           JLE  0040372A             ; EAX=0 Means Bad Reg...

; Do Something, sure... ;)
 004036BC 8D442438       LEA  EAX, [ESP + 38]
 004036C0 8D4C2418       LEA  ECX, [ESP + 18]
 004036C4 50             PUSH EAX
 004036C5 51             PUSH ECX
 004036C6 E895FAFFFF     CALL 00403160
 004036CB 83C408         ADD  ESP, 00000008
 004036CE 833D44F0480000 CMP  DWORD PTR [0048F044], 00000000
 004036D5 740B           JE   004036E2
 004036D7 A144F04800     MOV  EAX, [0048F044]
 004036DC 8BC8           MOV  ECX, EAX
 004036DE 8B18           MOV  EBX, [EAX]
 004036E0 FF13           CALL DWORD PTR [EBX]
 004036E2 833D40F0480000 CMP  DWORD PTR [0048F040], 00000000
 004036E9 740C           JE   004036F7
 004036EB A140F04800     MOV  EAX, [0048F040]
 004036F0 8BC8           MOV  ECX, EAX
 004036F2 8B18           MOV  EBX, [EAX]
 004036F4 FF5314         CALL [EBX+14]

; Close Registration Windows, And pops : "Thanks Registering"
 004036F7 6A01           PUSH 00000001
 004036F9 56             PUSH ESI
 004036FA FF15F4DA4900   CALL [USER32!EndDialog]
 00403700 6A00           PUSH 00000000
 00403702 6820324000     PUSH 00403220
 00403707 56             PUSH ESI
 00403708 FF15F8DA4900   CALL [USER32!GetParent]
 0040370E 50             PUSH EAX
 0040370F 68E4000000     PUSH 000000E4
 00403714 A148F04800     MOV  EAX, [0048F048]
 00403719 50             PUSH EAX
 0040371A FF1544DB4900   CALL [USER32!DialogBoxParamA]
 00403720 B801000000     MOV  EAX, 00000001
 00403725 E92EFFFFFF     JMP  00403658

; Pops up a window saying : "Your name and registration code do not match."
 0040372A 6A00           PUSH 00000000
 0040372C A104F34800     MOV EAX, [0048F304]
 00403731 50             PUSH EAX
 00403732 68ACF34800     PUSH 0048F3AC
 00403737 56             PUSH ESI
 00403738 FF15E4DA4900   CALL [USER32!MessageBoxA]
 0040373E 6882000000     PUSH 00000082
 00403743 56             PUSH ESI
 00403744 FF15F0DA4900   CALL [USER32!GetDlgItem]
 0040374A 50             PUSH EAX
 0040374B FF1548DB4900   CALL [USER32!SetFocus]
 00403751 B801000000     MOV  EAX, 00000001
 00403756 E9FDFEFFFF     JMP  00403658

    Let's do a some analysis on what we are seeing. We are at 0157:00403694
    (Your segment address may be different, it depends on what you load,
    update my values with yours). The previous instruction is the call to
    the GetDlgItmeTextA. Again, you can scroll in the code windows with
    "CTRL-UP", "CTRL-PGUP", "CTRL-DOWN" and "CTRL-PGDOWN". You can also
    make the Focus to the code window by pressing "Alt-C" and use the UP,
    DOWN, PGUP, PGDOWN to scroll it.

    In C, the call to the GetDlgItemTextA should look like this :

int GetWindowText (int windowhandle, char *buffer, int maxlen);
    So the push eax is the buffer address, let's have a look :

:d esp+18 ; You can also use "db esp+18" for byte display
    We've got it, it's our name ! We saw that in few intructions, there
    will be second call to the GetDlgItemTextA, the CALL EDI at
    0157:004036A4. We dont want Sice to break, so we will disable it :

:bd 4 ; Disable BP 4
    After that second call, there's another one followed by a test on the
    eax value... humm suspicious, is there any check inside that routine ?
    That's what we gonna determine fastly. We gonna trace the code stepping
    over function calls. Press P (Procedure trace) then ENTER (normally
    it's F10 key). Press it several times.

    After you've reached 0157:004036A6 (the second call) our registration
    code appears in the data window (if it is big enought, else you can
    scroll it down using Alt-DOWN) our predictions were right ;). You are
    now reaching the TEST AX,AX intruction (0157:004036BA), then there's a
    branch to another routine (0157:0040372A), the program will follow it
    and soon you will get a message saying that your registration code is
    wrong... (0157:00403738).

    So now we are sure that the call before the test was done to check the
    data we've enterred, and that the branch choose the direction to the
    Registration Not Match message. What if we change the direction the
    program took?

    Let's go, enable BP 4.

:be 4 ; Enable BP 4

    Leave Sice (CTRL-D), click on OK to get back to the registration
    window, and click on OK again to pop-up into Sice. Press CTRL-D another
    time to go to the second GetDlgItemTextA call and press F11 to go out
    of that function call. Now step to the branch (F10 until you reach
    0157:004036BA). And change the zero flag value to disable it:

:r fl z ; Toggle Zero Register FLag
    Then leave the proggy to himself (CTRL-D). We've done it ! The
    beautifull message appears : thanks for supporting our products, etc,
    etc...

    Hu Oh, Hey, what's that stupid program ? If i click on the little eye
    (the about button in the toolbar), it's telling me it is not registered
    !!!? Fucking damn thing, we gonna gotcha !

    Oki, let's think two seconds... what's the matter ? Well everything
    seems like if ACDSee checks the name and the registration at every
    times it shows them. So, to avoid this problem, we've got to give him
    the answer he wait each times he call the registration checker.
    First of all, we must verify our affirmations, we must know if the
    routine wich is called by the about button is effectively the piece of
    code into this call. Go into Soft-Ice using the BP we've set on the
    GetDlgItemTexta (go to the registration window and press enter), and
    press F11. Now, we're going to put another BP into the call.

:bpx 0157:00402FC0 ; Change the address in regard to yours
    Now we gonna try, leave Soft-Ice (it will pop-up two times because BP 4
    is still enabled, we're not interrested into these breaks), close the
    registration window by clicking cancel and finally click on the about
    button... Yep! back in Sice, we were right !!! So everything we've got
    to do now is to send back a satisfying answer to the calling code...

  Patching ACDSee

    Actually in your code window, you should have something like the
    following piece of code. All we've got to do is to leave this routine
    with EAX different from 0...

; Check Name Lenght
>00402FC0 56             PUSH ESI
 00402FC1 8B742408       MOV  ESI, [ESP + 08]
 00402FC5 56             PUSH ESI
 00402FC6 E835000000     CALL 00403000             ; check name length (1st)
 00402FCB 83C404         ADD  ESP, 00000004
!00402FCE 85C0           TEST EAX, EAX
!00402FD0 7504           JNE  00402FD6             ; branch is followed
!00402FD2 33C0           XOR  EAX, EAX             ; Set EAX to 0 (BAD!)
 00402FD4 5E             POP  ESI
 00402FD5 C3             RET                       ; Exit 1

; Check Registration Code
:00402FD6 8B44240C       MOV EAX, [ESP + 0C]
:00402FDA 50             PUSH EAX
:00402FDB 56             PUSH ESI
:00402FDC 6848F34800     PUSH 0048F348             ; "-294378973"
:00402FE1 E86AE70100     CALL 00421750             ; The key is herein (2nd)
:00402FE6 83C40C         ADD  ESP, 0000000C
:00402FE9 83F801         CMP  EAX, 00000001
:00402FEC 1BC0           SBB  EAX, EAX
:00402FEE 5E             POP  ESI
:00402FEF 40             INC  EAX
:00402FF0 C3             RET                       ; Exit 2

    So what we gonna do is erase the three instructions that works on EAX
    with our own code. Dont forget to change the address in regard to your.
    Erasing the branch will assure us that only our code will be followed.
    There's thousand of way to modify this code, i choosed the following :

:a 0157:00402FCE ; Assemble
0157:00402FCE mov eax,1
0157:00402FD3 nop
0157:00402FD3 ; Press escape to stop assembling
:bc 0  ; Clear BP on 0157:00402FC0

    And now let's check our work ! Press CTRL-D, welldone, the thanks for
    registering message appears... Okay, now click on the about button...
    (suspens) !!!YES!!! we've registered it.

    Oki let's do our work, now we've only got to make the patch...
    What we need to know is where are these instructions in the
    ACDSee32.exe file. I've use HexWorkShop for win95 and found them making
    a search for 85C0750433C0 (the instructions Opcodes, if Sice doesnt
    show the type "CODE ON") the one interesting us are at offset 23CE. Now
    we must make a little proggy to replace these bytes with our code. Here
    it is :

;--- ORP-A32B.ASM
        Title Patch For ACDSee 32 2.0 Beta
        .Model Huge
        .386
        .Stack 100h

        .Code
        mov     ax,cs
        mov     ds,ax
        mov     es,ax

        mov     ax,3d02h
        mov     dx,offset cs:fname              ; DX=*FileName
        int     21h                             ; DOS/FileOpen
        jc      errorlbl                        ; Jump On Errors

        mov     word ptr [offset cs:fname],ax   ; BX=Handle
        mov     bx,ax

        mov     ax,4200h
        xor     cx,cx                           ; Segment
        mov     dx,23ceh                        ; Offset
        int     21h                             ; DOS/FileSeekSet
        jc      errorlbl                        ; Error !

        mov     ax,4000h
        mov     bx,word ptr [offset fname]      ; BX=Handle
        mov     cx,6                            ; Lenght
        mov     dx,offset patch                 ; Buffer
        int     21h                             ; DOS/WriteFile
        jc      errorlbl

        mov     ax,3e00h
        mov     bx,word ptr [offset fname]      ; BX=Handle
        int     21h                             ; DOS/CloseFile
        jc      errorlbl

        mov     dx,offset cs:text2
        jmp     getout

errorlbl:
        mov     dx,offset cs:text1              ; Print
getout: mov     ah,9
        int     21h

        mov     ah,4ch                          ; Get Out Of Here !
        int     21h

patch   db 0B8H,001H,000H,000H,000H,090H        ; MOV EAX,00000001 - NOP
fname   db 'ACDSEE32.EXE',0
text1   db 0ah,0dh,'Error Handling File'
text2   db 0ah,0dh,'Patch By Exact /oRP',0ah,0dh,'$'
end;--- EOF ORP-A32B.ASM

    You can compile it with tasm 3.1 and tlink 5.1 (they can be found on my
    home page) in that manner :

TASM /m9 /n /q orp-a32b
TLINK /3 /x orp-a32b

    I think there is not so much comment to add at the source, anyway if
    you have any problems understanding what happening in there, you must
    find a book about programming (you can also try to get Helppc).

  Final Note

    Ok, this is the End...
    A really BIG thanks is going to ACP of UCF for sending me W32DASM !

    Have Fun With This Stuff !
    eXact /oRP
    aka sice_boy