Published by +Tsehp, November 2000.
Comment : A very useful essay to easily locate some general nagging functions.
Tools Used: SoftIce, W32Dasm, Win32 Programmer's Reference,
- An API monitor (i.e. APISpy32)
- The API Viewer, apiload.exe, that comes with the Visual Studio package to determine Constant values for API parameter flags. Available as a standalone package somewhere ;)
- A Windows Class Identifier (WinShow, Windowse). I used WinFrog which is FrogPrint's version of WinShow which displays the Hwnd in Hex instead of decimal (available at http://frogsprint.hypermart.net/main/tool.pl?GO)
Preamble: Greetings Reversers! Adware. A nasty concept in "freeware" development that makes it even more satisfying to reverse. Frazzle, a challenging 5-star rated puzzle game, is a typical Adware program that displays its own advertisements in a banner header. If you are connected to the Internet and click on the banner, it downloads more ads via advert.dll and inundates your senses even further. I'm sorry but this type of behaviour is just begging to be reversed ;-)
General Structure and Code Flow:
The program is written in MS Visual C++ 5.0. Above the main "puzzle" part of the program proudly flies the Ad Banner, and next to it an About button. At the bottom is a row made up of the rest of the controls. After retrieving the Taskname in SoftIce with 'Task', type 'Hwnd [Taskname]' to get a view of all the Controls (windows) in the program and their relationship to each other. You can see from the table below that most of the Controls are Child windows of the main Parent window AfxFrameOrView42s. I've only included the Window Handle (Hwnd, which changes each time the program is run) and Class Name from the Hwnd command and added a Description.
|Window Handle||Class Name||Description|
|07FC(2)||AfxWnd42s||Ad Banner window|
Now that we have an idea of the individual components making up the program, what we're going to want to do is:
1. Eliminate the Ad Banner window.
2. Eliminate the About button because it happens to be next to the Ad Banner window and is in the way.
3. Move the main Puzzle window up and increase its size to cover the blank space left by 1. and 2.
4. Get rid of the Nag when you delete advert.dll from your system.
There are 3 API's that we need be concerned with - CreateWindowExA, ShowWindow and SetWindowPos.
The CreateWindowEx function creates an overlapped, pop-up, or child window with an extended style.
Monitoring CreateWindowExA is used here more to keep tabs on what is going on and to have a reference to the Hwnds.
|The ShowWindow function sets the specified window's show
Specifies how the window is to be shown. This parameter is ignored the first time an application calls ShowWindow, if the program that launched the application provides a STARTUPINFO structure. Otherwise, the first time ShowWindow is called, the value should be the value obtained by the WinMain function in its nCmdShow parameter. In subsequent calls, this parameter can be one of the following values:
SW_HIDE Hides the window and activates another
We'll change the ShowWindow nCmdShow parameter value from its default of SW_SHOW = 5 to SW_HIDE = 0 to eliminate the Ad Banner window.
|The SetWindowPos function changes the size, position, and
Z order of a child, pop-up, or top-level window. Child, pop-up, and
top-level windows are ordered according to their appearance on the screen.
The topmost window receives the highest rank and is the first window in
the Z order.
X - Specifies the new position of the left side of the
All coordinates for child windows are client coordinates (relative to the upper-left corner of the parent window's client area).
SWP_NOACTIVATE Does not activate the window. If this flag
is not set, the window is activated and moved to the top of either the
topmost or non-topmost group (depending on the setting of the
We'll use the SetWindowPos uFlags parameter to get rid of the About button by changing it from SWP_SHOWWINDOW = 40 to SWP_NOACTIVATE = 10.
And to cover up the blank space left, we'll modify the SetWindowPos call of the Puzzle window AfxWnd42s by resetting its values for Y and cy.
OK, the next thing to do is to take a look at the API monitor output. I've included all the pertinent calls so you get an idea of the code flow. It may be a little confusing to read, but hey, that's the output ;). All the Calls are listed in the order in which they occur, and I've grouped them into 3 tables so they can (hopefully) be easier to read. I've also highlighted the Calls we'll be dealing with directly.
Each Call is listed as a pair of lines, the 1st is the Call itself and is composed of the address of the Call, the name of the Call, and then within the brackets, each of the stack parameter values before the call is made. The 2nd is the Return value (for CreateWindowExA the Return value is the Hwnd, for the others it's generally just a zero/nonzero flag).
A few things to note:
- If you check carefully, you see that all the CreateWindowExA calls for the Child windows are bracketed within the CreateWindowExA call for the Parent window. This is important to note so you don't get screwed up when tracing in SoftIce. The CreateWindowExA call for the main window AfxFrameOrView42s does not return until all the other CreateWindowExA calls are finished. I've indented the Child window calls to highlight this.
- The same applies for ShowWindow for AfxFrameOrView42s, each of the Child windows goes through a SetWindowPos call before ShowWindow returns.
- When you start the program for the 1st time, a file "Prefs.SAV" is produced. As well as having information on any customizing of puzzles you do, it also contains the default height and width of the parent window. If you resize the program it modifies these values (242 and 186) and remembers them next time. This is the function of CreateFileA and ReadFile. This has nothing to do with the Ad window, but I include it anyway.
DWORD:80000000, DWORD:00000000, LPDATA:0069FC78, DWORD:00000003,
0041D0B3:CreateFileA = 14
0041D10B:ReadFile(HANDLE:00000014, LPDATA:010D34CC, DWORD:00001000, LPDATA:0069FC9C, LPDATA:00000000)
0041D111:ReadFile = 1
0041A40B:CreateWindowExA(DWORD:00000200, LPSTR:004277E0:"AfxFrameOrView42s", LPSTR:0042D0F8:"Frazzle", DWORD:000F0000, DWORD:0000000A, DWORD:0000000A, DWORD:0000021A, DWORD:0000017C, HWND:00000000, HANDLE:00000000, HANDLE:00400000, LPDATA:00000000)
0041A411:CreateWindowExA = 978
00419002:ShowWindow = 0
OK, I hope the tables help you navigate through the output and understand how to isolate and home in on the components that need reversing. Now, back to what we're trying to do.
1. Eliminate the Ad Banner window:
We need to change the ShowWindow nCmdShow parameter value from its default of SW_SHOW = 5 to SW_HIDE = 0 to eliminate the Ad Banner window.
00418FFC: ShowWindow(HWND:000007FC, DWORD:00000005)
You see from the API monitor output that the Call is at 418FFC and is the 1st ShowWindow call encountered. So if you load the program with SoftIce loader32.exe and set a BPX 418FFC and press F5, SoftIce will break on that address.
:00418FF5 PUSH DWORD PTR [ESP+04]
:00418FF9 PUSH DWORD PTR [ECX+1C]
:00418FFC CALL [USER32!ShowWindow]
Type "dd ESP" while you are ON 418FFC to display the stack parameters of the Call and confirm you have the right call:
:0069F878 000007FC 00000005
Now return from the "call to the Call" by F10 stepping over the ShowWindow call until you reach a RET, or just press F12, and you'll RETurn to 407ECC. Notice the code above it and you see
:00407EC3 6A05 PUSH 05
:00407EC5 MOV ECX,ESI
:00407EC7 CALL 00418FEE ; to ShowWindow
:00407ECC MOV EAX,[ESI+1C]
The PUSH 05 statement PUSHes the value of 05 onto the stack of the Call at :00407EC7 and becomes DWORD PTR [ESP+04] in the ShowWindow Call, or the nCmdShow parameter value of SW_SHOW = 5. To change it to SW_HIDE = 0 and get rid of the Ad Banner window, we simply change
:00407EC3 6A05 PUSH 05
:00407EC3 6A00 PUSH 00
You can use W32Dasm to find out that address 407EC3 is at hex location 72C3 in the file and make the change in a hex editor.
Et Viola, no more Ad window! Just like that, careful use of an API monitor yields us a victory, no fuss no muss ;-)
2. Eliminate the About button:
Use the SetWindowPos uFlags parameter to get rid of the About button by changing it from SWP_SHOWWINDOW = 40 to SWP_NOACTIVATE = 10.
00418FC6: SetWindowPos(HWND:00000E84, HWND:00000000, DWORD:000001D4, DWORD:00000000, DWORD:0000003A, DWORD:0000003C, DWORD:00000040)
Notice in the API output listing that the About button is dealt with in the 2nd SetWindowPos call at 418FC6. If you set a BP on this address and allow SoftIce to break twice you reach:
:00418FB3 PUSH DWORD PTR [EBP+1C]
:00418FB6 PUSH DWORD PTR [EBP+18]
:00418FB9 PUSH DWORD PTR [EBP+14]
:00418FBC PUSH DWORD PTR [EBP+10]
:00418FBF PUSH DWORD PTR [EBP+0C]
:00418FC2 PUSH EAX
:00418FC3 PUSH DWORD PTR [ECX+1C]
:00418FC6 CALL [USER32!SetWindowPos]
And a "dd ESP" displays the stack
:0069FA54 00000E84 00000000 000001D4 00000000
:0069FA64 0000003A 0000003C 00000040
Now if you RETurn from the "call to the Call" as before you spy the following code. Note that this comes immediately after the 1st SetWindowPos call for the Puzzle window RET, which we'll deal with later.
:00401BE4 CALL 00418F9F ; SetWindowPos call
for Puzzle window
:00401BE9 MOV EBX,[ESP+28]
:00401BED MOV EDX,[ESP+20]
:00401BF1 SUB EBX,EDX
:00401BF3 6A40 PUSH 40 ; SWP_SHOWWINDOW uFlag parameter
:00401BF5 SUB EBX,000001D4
:00401BFB PUSH 3C
:00401BFD PUSH EBX
:00401BFE LEA EBP,[ESI+000032F4]
:00401C04 PUSH 00
:00401C06 PUSH 000001D4
:00401C0B PUSH 00432AF0
:00401C10 MOV ECX,EBP
:00401C12 CALL 00418F9F ; SetWindowPos call for About button
SoftIce helps confirm that the PUSH 40 statement is where the uFlags parameter SWP_SHOWWINDOW is set to 40. We want to change it to SWP_NOACTIVATE = 10 by changing
:00401BF3 6A40 PUSH 40
at FF3h to
:00401BF3 6A10 PUSH 10
Done. Now we've got a nice big blank space where the Ad Banner and About button used to be. Let's make it more aesthetically pleasing...
3. Move the main Puzzle window up and increase its size to cover the blank space left by 1. and 2.:
We need to modify parameters 4 and 6 of SetWindowPos, vertical position Y and height cy.
00418FC6: SetWindowPos(HWND:00000E7C, HWND:00000000, DWORD:00000000, DWORD:0000003C, DWORD:0000020E, DWORD:000000FE, DWORD:00000040)
Proceeding as above, the stack for the SetWindowPos Call:
:0069FA54 00000E7C 00000000 00000000 0000003C
:0069FA64 0000020E 000000FE 00000040
Notice that of the 3rd and 4th stack parameters, only the 4th or the Y vertical position of the Puzzle window relative to the upper-left corner of the parent window is defined (3C). This is of course to allow for the height of the Ad Banner that lies above it, which is set in the 8th stack parameter of the Ad window CreateWindowExA call. The height of the About button is updated to 3C in its SetWindowPos call to allow it to fit into the space allocated.
Examing the code preceding the Call:
:00401BB1 CALL [USER32!GetClientRect]
:00401BB7 MOV EDI,[ESP+2C] ; 158h = total height allocated to fit in all the controls in the program's main window
:00401BBB MOV ECX,[ESP+24] ; 0
:00401BBF SUB EDI,ECX ; edi remains 158h
:00401BC1 MOV EAX,[ESP+28] ; 20E = width of main window
:00401BC5 SUB EDI,1E ; total height - height of bottom row of buttons = 13A remaining
:00401BC8 PUSH 40 ; SWP_SHOWWINDOW uFlag parameter
:00401BCA LEA ECX,[ESI+00003070]
:00401BD0 8D57C4 LEA EDX,[EDI-3C] ; [13A - height of Ad window] = FE remaining
:00401BD3 PUSH EDX ; height left over for Puzzle window = FE
:00401BD4 MOV EDX,[ESP+28] ; 0
:00401BD8 SUB EAX,EDX ; 20E - 0 = 20E
:00401BDA PUSH EAX ; width = 20E
:00401BDB 6A3C PUSH 3C ; vertical "y" offset of Puzzle window from upper left corner
:00401BDD PUSH 00 ; "x"
:00401BDF PUSH 00432AF0
:00401BE4 CALL 00418F9F ; SetWindowPos
There's 2 things we need to do here. One is to change the "y" position from
:00401BDB 6A3C PUSH 3C
:00401BDB 6A00 PUSH 00
at hex location FDB
And the other is to increase the height of the window to fill in that space. You can see that
:00401BD0 8D57C4 LEA EDX,[EDI-3C]
takes into account the height of now non-existent Ad window, so we can dispense with the 3C offset and change this to
:00401BD0 8D17 lea edx, dword ptr [edi]
:00401BD2 90 nop
at hex location FD0
That about does it except for
4. Get rid of the Nag when you delete advert.dll from your system:
Simple enough trace using MessageBoxA to find that FindFirstFileA is used to
check if the file exists when you select some of the functions (some irrelevant
code missing below)
* Referenced by a CALL at Addresses:
|:0040191B , :0040194B , :00401A24 , :0040247E , :00402498
:004025A0 A118124300 mov eax, dword ptr  ; a flag in the uninitialized section of .data in memory, always 0
:004025A5 81EC40010000 sub esp, 00000140
:004025AB 85C0 test eax, eax
:004025B1 740B je 004025BE ; I changed this to 7400 je 4025B3 to miss the FindFirstFileA call entirely
:004025B3 B001 mov al, 01
:004025BD C3 ret
* Referenced by a (U)nconditional or (C)onditional Jump at
:004025BE 8D442408 lea eax, dword ptr [esp+08]
:004025C2 C7051812430001000000 mov dword ptr , 00000001
:004025CC 50 push eax
* Possible StringData Ref from Data Obj
:004025CD 6884D14200 push 0042D184
* Reference To: KERNEL32.FindFirstFileA,
:004025D2 FF1524674300 Call dword ptr 
:004025D8 83F8FF cmp eax, FFFFFFFF
:004025DB 7426 je 00402603
* Reference To: KERNEL32.FindClose, Ord:007Eh
* Referenced by a (U)nconditional or (C)onditional Jump at
|:004025DB(C), :004025EE(C), :004025F6(C)
:00402603 6A10 push 00000010
* Possible StringData Ref from Data Obj
:00402605 687CD14200 push 0042D17C
* Possible StringData Ref from Data Obj ->"ADVERT.DLL is
missing or corrupt!"
:0040260A 6858D14200 push 0042D158
:0040260F 8BCE mov ecx, esi
:00402611 E855DA0100 call 0042006B ; MessageBox
There you have it. Pretty straightforward if you can sort out the sequence of API calls. Nothing beats a good API monitor and the Win32 Programmer's Reference ;-) But is the program truly "reversed" by modifying its window display properties? Well yes and no. Visually it is of course, and no longer can it connect to its home page if you inadvertently click on the Ad window. But in the background there is still processing going on which is trying to alternately display a couple of its own advertisements (which are built-in bitmap Resources BTW), with calls to GetWindow, CallWindowProcA, DefWindowProcA, GetTopWindow etc. This seems to indicate that we can't get rid of the Ad Banner CreateWindowExA call entirely without a major code overhaul. Interestingly, if you move the Puzzle window (step 3) before removing the Ad window and About button, the ads still show through as they are redrawn. You can actually see the 3 windows competing with each other as they are refreshed.
So if you want to have a go at stomping out these in-your-face CPU-sucking billboards, there's plenty of sites specializing in 'Adware'. Anyway, if you have any questions or comments I'd love to hear from you, just don't send me any Ads...
Big Greetz and Hurrahs to the new improved RCE Regroupment Board. Long may you live and Reverse.