home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Quantico / tutors / hnpad.txt < prev    next >
Encoding:
Text File  |  2000-05-25  |  90.0 KB  |  1,973 lines

  1. _______________________________________________________________________________________________
  2.  
  3. REVERSING, FUNCTIONS ADDITION, MODIFICATIONS IN THE EXISTING CODE AND CLASSIC CRACKING IN
  4. A TYPICAL TARGET FROM MICRO$OFT: NOTEPAD.EXE....DETAILED DESCRIPTION OF THE CREATION OF
  5. HNOTEPAD
  6.  
  7. REVISION 1
  8.  
  9. By -NeuRaL_NoiSE 1999
  10. _______________________________________________________________________________________________
  11.  
  12.  
  13. Some time ago, I was saying....
  14.  
  15.  
  16. " Hiho!
  17.  
  18. So here we go again with Micro$oft-related stuff...after my last tutorial (about shell32.dll
  19. reversing), i decided to stop having to do with Micro$tuff...alas it looks like i can't get rid
  20. of it :D
  21. In this tute i'll give a detailed explanation about how to modify notepad.exe (and in general,
  22. many other programs) in order to add/remove/modify some functions, to better adapt it to the
  23. project that me and two friends of mine, Anub|s and Insanity are trying to get to an end. In a
  24. few words, this project is about modifying notepad.exe and creating a .hlp file which will
  25. contain every info needed to program in raw html. Their duty was to create the help (i suck
  26. when it comes to program html :) and mine was to reverse engineer notepad.exe and add the
  27. necessary new functions. Of course the .hlp file will be (it's not ready yet) in italian (since
  28. we are all italians, tho i'll ask my friends if they will translate it into english as well)."
  29.  
  30. I already published a tutorial about Hnotepad creation, but as you may have noticed this last
  31. tute only pointed to Windows 95 compatibility, no Win98, and above all you should have noticed
  32. that code generation was strictly related to the machine where you were assembling it. I myself
  33. was suggesting to work on it, but in the end i finished it, making the code more portable and
  34. stable...so here i'll describe you how, with a few additions/side changes, your code will work
  35. under both 95 and 98.
  36.  
  37. Another improvement from last tute is in the fact that after you've made the changes i describe
  38. in the last phase of this document your Notepad will read files much bigger than the usual FFFF
  39. bytes (special thanks to GEnius for his GENIAL idea :), but mind, i say you will be able to READ
  40. them, not WRITE on them -- do u remember that insufficient mem nag ? I thought i'd leave it
  41. there, it might be useful to have a nag that reminds you when your page is exceeding 50/60 Kb...
  42. Nonetheless i might change that as well in some next version, who knows - hnotepad is a pretty
  43. open project, and it's amazing the number of friends that are asking me to improve it and add
  44. functions :)
  45.  
  46.  
  47. ___________________________
  48.  
  49. PART 1: PRELIMINARY REMARKS
  50. ___________________________
  51.  
  52.  
  53. As i said, this tutorial wishes to introduce intermediate (this won'be for COMPLETE newbies)
  54. crackers to the world of reverse engineering, in its (imho) most interesting aspect: ADDITION
  55. OF FUNCTIONS IN AN ALIEN TARGET. That's it, really simple...you'll discover (if u didn't know
  56. it yet) that it's not such a monster to add your new stuff to targets.
  57. I'll try to explain things in the easiest and most extensive way i can, tho i warn you about
  58. three things: first, you *MUST* have a (at least) basic knowledge of w32 assembly language and, in
  59. general, of cracking (furthermore, i STRONGLY suggest reading something about pe headers and
  60. Windows executable files structure as it'll help alot).
  61. Second, my english sucks so please consider that it is a great effort for me to translate this
  62. whole (damn LONG:) tute -- italian version at http://ringzer0.cjb.net .
  63. Third, READ THIS TUTORIAL *WITHOUT* THE WORDWRAPPING, OR YOU WON'T UNDERSTAND MUCH :)
  64.  
  65.  
  66. IMPORTANT : Even if this tutorial describes the creation of a portable version of Hnotepad (good
  67. for both 95 and 98), i'll use the Notepad.exe file that comes with WINDOWS *95*...so i suggest
  68. you use the same file i used (for the english translation, i used notepad.exe in english so u
  69. should have no problems finding it around).
  70.  
  71.  
  72.  
  73. TOOLS USED:
  74. ___________
  75.  
  76. * W32Dasm v8.93
  77. * SoftICE v3.24
  78. * HIEW v6.1
  79. * Borland Resource Workshop (BRW) v4.5
  80. * ProcDump32 v1.3
  81. * API Reference
  82.  
  83.  
  84.  
  85.  
  86. __________________________
  87.  
  88. PART 2 : INTRO TO HNOTEPAD
  89. __________________________
  90.  
  91. Here's what we'll do in this tutorial:
  92.  
  93. * We'll add a menu to Notepad, that will open our new .hlp file
  94.  
  95. * We'll create the about box (as for now there isn't a REAL about box, but u'll understand
  96.   later)
  97.  
  98. * We'll find the way to add "HTML Files" (both *.htm and *.html), "JS Files" and "VBS Files" to
  99.   the masks (*.xyz) in the "Open file" and "Save as" dialogs
  100.  
  101. * We'll add a nice .INI file, where we'll save the status of the WordWrapping option and the
  102.   name of the last file opened. When restarting hnotepad, wrapping will be put in the position
  103.   (ON/OFF) indicated in the file, and the last file will be automatically reopened if we
  104.   launched hnotepad without command line. Furthermore, this .INI file will be automatically
  105.   created every time we'll quit the program, so there'll be no problem related to
  106.   modifying/damaging it.
  107.  
  108. * We'll eliminate the size limit of the opened file. In order to do this, we'll need an API
  109.   function which is not imported with original notepad, tho we won't touch the import table.
  110.   Rather, we'll use a piece of memory scanning code, which, as you'll see if you continue
  111.   reading, will probably be REALLY useful for you reversers out there who have not yet noticed
  112.   this interesting alternative to GetProcAddress.
  113.  
  114. That's all, we can start!
  115.  
  116.  
  117. _________________________________
  118.  
  119. PART 3 : THE CREATION OF HNOTEPAD
  120.  
  121. PHASE 1 : THE NEW MENU
  122. _________________________________
  123.  
  124.  
  125. So....first of all let's try to understand WHAT we will do to our target: we have to ADD a menu
  126. to those already existing in the program....but let's keep in mind that during the session
  127. we'll surely have to add parts of OUR own code to the file....in the case of the menu, we'll
  128. have to add that part of the window procedure that analizes the selected menu IDs relative to
  129. our new menu. So we'll first of all take a look at how our target behaves when it has to
  130. analize menu IDs (as you know every item, from menus to buttons on dialog boxes and so on, have
  131. an ID that is needed to allow the program to distinguish among various resource items)....we
  132. could climb back to window procedure using the API RegisterClass as hook but we'll follow
  133. another route, a quicker one....we'll get right to the point that interests us. We said that we
  134. want to add a menu....so we will start looking at HOW the program behaves when you select a
  135. menu: the API we'll break on will be WinHelpA (which runs the file winhelp.exe under \windows,
  136. that is needed to open any .HLP file, of course if in windows help format). In SoftICE, then,
  137. "BPX WinHelpA".
  138. Then go to notepad, and select menu "Help", then the item "Help topics".
  139. Sice will break on WinHelpA: F12 and u'll be at the caller, which is here:
  140.  
  141. :00401E51 FF7514                  push [ebp+14]
  142. :00401E54 57                      push edi
  143. :00401E55 FF7508                  push [ebp+08]
  144. :00401E58 E80FF3FFFF              call 0040116C    ; <-- WE COME BACK FROM THIS CALL
  145. :00401E5D 85C0                    test eax, eax
  146. :00401E5F 0F8582000000            jne 00401EE7
  147. :00401E65 FF7514                  push [ebp+14]
  148. :00401E68 57                      push edi
  149. :00401E69 56                      push esi
  150. :00401E6A FF7508                  push [ebp+08]
  151.  
  152. * Reference To: USER32.DefWindowProcA, Ord:0078h
  153.                                   |
  154. :00401E6D FF1534744000            Call dword ptr [00407434]
  155. :00401E73 EB74                    jmp 00401EE9
  156.  
  157.  
  158. Good...DefWindowProcA indicates the part of the window procedure where the messages are
  159. processed by default (ie when you don't process a certain message, this msg won't just "fall
  160. somewhere" but will be "catched" anyway by DefWindowProcA which will process it accordingly).
  161. This means that the menu value passes for (and is checked by) that call at 1E58 (it's parameter
  162. 2/3, the one in EDI) where we are coming back from.
  163. Let's see what's inside the call:
  164.  
  165. * Referenced by a CALL at Address:
  166. |:00401E58  
  167. |
  168. :0040116C 55                      push ebp
  169. :0040116D 8BEC                    mov ebp, esp
  170. :0040116F 81EC04010000            sub esp, 00000104
  171. :00401175 33C0                    xor eax, eax
  172. :00401177 56                      push esi
  173. :00401178 57                      push edi
  174. :00401179 BE38614000              mov esi, 00406138
  175. :0040117E 8DBDFCFEFFFF            lea edi, dword ptr [ebp+FFFFFEFC]
  176. :00401184 B940000000              mov ecx, 00000040
  177. :00401189 A4                      movsb
  178. :0040118A 8DBDFDFEFFFF            lea edi, dword ptr [ebp+FFFFFEFD]
  179. :00401190 F3                      repz
  180. :00401191 AB                      stosd
  181. :00401192 66AB                    stosw
  182. :00401194 AA                      stosb
  183. :00401195 0FB7750C                movzx esi, word ptr [ebp+0C] ; <- ID VALUE OF THE CHOSEN MENU
  184. :00401199 83FE20                  cmp esi, 00000020 ; COMPARES ID VALUE AND 20h
  185. :0040119C 8BC6                    mov eax, esi
  186. :0040119E 7F1A                    jg 004011BA       ; IF ID > 20h, TAKE THE JUMP
  187. :004011A0 0F84C1030000            je 00401567
  188. :004011A6 48                      dec eax
  189. :004011A7 83F81B                  cmp eax, 0000001B
  190. :004011AA 7736                    ja 004011E2
  191. :004011AC 0FB68838174000          movzx ecx, byte ptr [eax+00401738]
  192. :004011B3 FF248DF8164000          jmp dword ptr [4*ecx+004016F8] ; OTHERWISE PROCESS
  193.                                                                  ; ACCORDINGLY
  194.  
  195. So we have the menu ID (you can check all values with BRW, under "MENU") in esi, then a check
  196. if esi>20h. 20h is 32 dec, so we know that the IDs with value < than 32 will be processed by a
  197. variable jump, which will change from situation to situation, and will point every time to the
  198. appropriated part of code (the jmp at 11B3). So, if we don't want to mess up, we'll better give
  199. our menu an ID value > than 32, so that we will be able to process it following the jg at 119E,
  200. which brings here:
  201.  
  202.  
  203. * Referenced by a JUMP at Address:
  204. |:0040119E(C)
  205. |
  206.  
  207. * Possible Ref to Menu: MenuID_0001, Item: "Cut   Ctrl+X"
  208.                                   |                                 
  209. :004011BA 3D00030000              cmp eax, 00000300 ; 300h (768 dec) = "Cut" menu item
  210. :004011BF 7C21                    jl 004011E2
  211.  
  212. * Possible Ref to Menu: MenuID_0001, Item: "Copy   Ctrl+C"
  213.                                   |
  214. :004011C1 3D01030000              cmp eax, 00000301
  215. :004011C6 0F8E0F030000            jle 004014DB
  216.  
  217. * Possible Ref to Menu: MenuID_0001, Item: "Paste   Ctrl+V"
  218.                                   |
  219. :004011CC 3D02030000              cmp eax, 00000302
  220. :004011D1 0F8427030000            je 004014FE
  221. ..............
  222. ..........
  223.  
  224.  
  225.  
  226. and so on with the other checks. So we found a good point to insert a deviation to OUR code,
  227. which will process FIRST the ID value relative to the new menu. But first we'll have to CREATE
  228. this menu, don't you think ? :)
  229. In order to do so, open notepad.exe in BRW and, under "menu" section, and under "Help" menu,
  230. add a new item, I called it "Anub|s+Insa's Help on HTML". Give it the id value 33 (21h), that
  231. is useful because as we said with an id value bigger than 20h the part of the code which will
  232. process the id will be the one after the jg, not the one reached after the variable jump. Any
  233. value higher than 32 will do just fine (of course it must not be related to any other item).
  234. Now, in the "KEY" section, add "VK_F1", which will make THIS menu pop up when we press F1 (and
  235. not the old Notepad's one). Don't forget to delete the same key from old notepad's menu.
  236. Save, and like some kinda magic when you next start notepad you'll have this new menu under
  237. "Help", which will have as you know an id value of 21h.
  238. So now we must solve the problem of the addition of our code to the file. How can we do this??
  239. Well we must check a thing or two first. If you open the file with HIEW, with ProcDump or with
  240. god only knows how many other programs, u'll have all the infos you need to add you own code. Of
  241. course, as you know, we can't occupy MORE bytes than the ones we have in the actual code (which
  242. resides in .TEXT section), so we are compelled to APPEND our code to the end of the file, so that
  243. afterwards we will be able to redirect jumps from PE .TEXT section to the section where we added
  244. the code, which is the one we'll see in a few. Usually when you want to add your own code, the
  245. last section will be just fine for the trick. BUT, in notepad case, we already added a new menu,
  246. and this addition has brought to the extention of the .RSRC (resource) section in the pe
  247. header...so BRW has appended this section at the end of the file in order to not overwrite the
  248. bytes of the following section (in other words, it has done something similar to what we want to
  249. do:)...you can easily check it by entering HIEW, pressing F8 (from hex or disasm mode) to see the
  250. header-related infoes, then F6 for the sections. So i was saying, the pe (and the file) has now
  251. been modified by BRW, but we must keep in mind that "natively" notepad.exe ended with the .RELOC
  252. section, where we could actually find therefore some free space for our code, and which, for this
  253. reason, is the one where we'll go and add our code (at least for the first part of it, because
  254. we'll soon be out of space and we'll have to continue within .RSRC). The first thing to do is
  255. checking the physical space (i'm talking about BYTES) we have for our code: so we check the
  256. Virtual Size (VirtSize = 91Eh) and the Physical one (PhysSize = A00h); the virtsize shows us the
  257. number of bytes that we can't modify, in other words the ones already used by the program, while
  258. the physsize shows us the raw size of the section: a simple subtraction A00h-91Eh will give us
  259. E2h (226 dec.) free bytes , in which we will be able to add our code. We won't need to enlarge
  260. the section, because we have all the space we need; if you had to enlarge it, BEFORE creating the
  261. menu with BRW, you would have loaded the file with ProcDump, edited the section, and increased
  262. the physical size to whatever you needed. Good! But we still have a problem...how can we know at
  263. WHICH OFFSET we should add our code ? Easy...we
  264. must look at the section's intial offset: we know that it's 5000h, so Initial_Offset+VirtSize =
  265. 5000h+91Eh = 591Eh, our entrypoint for code addition. Yet we have ANOTHER problem....WHICH code
  266. should we add ? :))
  267. First of all, let's draw a scheme of the operations we want our code to perform. To make the
  268. code jump from .TEXT section (where we have that call that processes the ID values) to the
  269. .RELOC one (where our code will be), we'll necessarily need to turn some instruction to a
  270. jmp....we'll modify the CMP at 11BA: so we have to find a way to turn that cmp to a jump TO
  271. ANOTHER SECTION: this could have caused problems to a cracker once, because one poor guy who
  272. wanted to add his code to targets was usually compelled to use a compiler in order to generate
  273. valid opcodes to add to the existing code, and this implied wasting time with first section and
  274. last one's RVA subtractions and so on...then, one nice day SoftICE appeared into our pc's,
  275. along with his "A" function (Assemble instruction) :))))))))
  276. Thanks to this great tool, we can assemble the instructions at runtime, time by time, and
  277. obtain thus the valid opcodes with which we'll physically patch the target afterwards. In order
  278. to see the bytes beside every code line in SoftICE, insert "CODE ON" either at command prompt
  279. or in your winice init string. The opcodes will be universal for PUSHes, CMP's and so on, so
  280. for THIS kind of instructions we can use HIEW directly, but for long JUMPS we'll need SoftICE,
  281. because the distance between the starting offset and the destination one isn't easily obtainable
  282. with HIEW when it comes to long jumps (expecially if we're hopping between 2 sections). Yes ok
  283. for the jumps then, but what about the CALLS ?? Simple...a call to an API function (thing that
  284. we'll use) is nothing more than a call to a dword pointer, which points to a specific offset in a
  285. section called .IDATA (imported data): every single API that is used by our program is included
  286. in this section at compiling time, and in order to use it from our code we'll have to use CALL
  287. [DWORD_PTR_TO_THE_API]. To discover which dword pointer we'll have to call in order to invoke a
  288. certain API, we'll use W32Dasm. Every single API call will correspond to a CALL DWORD PTR [xyz]
  289. (you can look that up really easily by making a search inside the disasm): everytime u'll need
  290. that API you'll call that pointer from hiew, nothing more nothing less.
  291.  
  292. This semplifies our job ALOT, but you may be asking one thing now...HOW do we know, from
  293. SoftICE, WHERE (to which offset) we should jump to from section .TEXT to reach our code ?? We
  294. can't find the location with W32Dasm because the disassembled part only concerns .TEXT section,
  295. not .RELOC (where our code will be)...the solution resides in HIEW: open notepad.exe
  296. with hiew: switch to HEX or DISASM mode, then press ALT+F1 until you have selected LOCAL in the
  297. way hiew will display offsets. You'll notice that, if you had "global" before, now there'll be a
  298. difference in the way the offsets are showed: indeed, not offsets anymore, but complete VA's
  299. (Virtual Addresses, = RVA+Image Base of the location), which are everything we have to know in
  300. order to assemble a valid jump in softice. So we'll just assemble a "JMP VA_of_our_new_code", and
  301. sice will give us the correct opcodes. Only for short jumps (within a certain code range, or for
  302. those with 2 opcodes and so on) we don't need sice, but we can insert the offset directly in
  303. HIEW, because the jump won't exit from a short code range, and HIEW is still ok for opcode
  304. generation. So from now on, when you see some asterisks (*******) beside the instruction, it
  305. means that it has been assembled with softice, and that i patched the file with the bytes that it
  306. gave me back.
  307.  
  308. Another problem...we said that we have to make the program open a new file with this menu,
  309. which will be Anub|s and Insanity's file on HTML programming...this file will surely have a
  310. name (something.hlp), even if i don't know yet (but nor do them i believe :))), anyway we'll
  311. use a demonstrative name here, and it'll be HNOTEPAD.HLP. So i was saying, we have to make the
  312. code recognize the name "HNOTEPAD.HLP" as well, but of course this name isn't present anywhere in
  313. the code...so we'll have to add it to our target's STRINGTABLE. The stringtable is nothing more
  314. than the place where we can find all the strings among the resources of the program. We could
  315. turn some old string into our new "HNOTEPAD.HLP", or we could append it (the 'raw' way;) to the
  316. code of our target (thing that we'll do later in this tutorial, and that is useful when you can't
  317. gain access to a program's resources), but considered that we have access to the resources, we'll
  318. ADD it to the stringtable and we'll treat it just as any other string already existing. So the
  319. first step is, in BRW, to select the LAST stringtable (# 48), press the right mouse button and
  320. EDIT IT AS TEXT (be careful not to edit it only, or you won't be able to add items to the table).
  321. Once you are in the table, just add this line at the end:
  322.  
  323.  58, "hnotepad.hlp"
  324.  
  325. Save the file, and you're done! Now we have a brand new string, that we'll be able to use from
  326. the code at our will...do you start to see the HUGE possibilities that appear before us?? :)
  327. So...now you have to know (if you didn't know it already:) that strings are loaded from the
  328. stringtable with the LoadStringA function, whose prototype is:
  329.  
  330. int LoadString(
  331.  
  332.     HINSTANCE hInstance,// handle of module containing string resource
  333.     UINT uID,            // resource identifier (in our case 58, or 3Ah)
  334.     LPTSTR lpBuffer,    // address of buffer for resource
  335.     int nBufferMax     // size of buffer (# of chars to take from the string: if the string is
  336.                         // shorter it's ok, but if it's longer it will be truncated!
  337.    );
  338.  
  339.  
  340. Hmmm....the problem here is the buffer....how do we know which buffer we should use for our new
  341. string? Well, we just need a little experience with the program i'd say....start setting
  342. breakpoints, and you'll pretty soon find a buffer good for our new resource. You have two
  343. choices:
  344. 1 - finding a buffer which is loaded ONLY ONCE (at program execution): in this case you'll have
  345. to use LoadStringA one more time, like some sorta PUSH and POP with the buffer.
  346. 2 - finding a buffer that is loaded EVERY TIME the program needs the string which is supposed
  347. to fill that buffer....in this case, you won't have to worry about replacing the new string
  348. with the old one once u're done with it, because it will be the program itself to do the job
  349. for you. This last one is definately the best choice, as it avoids us coding bigger routines.
  350. So, let's take a look around us..let's take the messagebox that says "This file is too large
  351. for Notepad to open...wanna use Wordpad??"...if u choose "yes", you'll notice a LoadStringA
  352. that loads the variable "wordpad.exe" into a buffer, which is needed to run the program
  353. (wordpad)...here's the disasm (keep in mind that the values are pushed on the stack in reverse
  354. order):
  355.  
  356. :00402D70 6804010000              push 00000104 ; PUSHES # OF CHARS TO TAKE FROM THE STRING
  357. :00402D75 8D85B8FEFFFF            lea eax, dword ptr [ebp+FFFFFEB8] ; EAX BECOMES=63F8C4h
  358. :00402D7B 50                      push eax ; PUSHES 63F8C4h AS BUFFER TO RECEIVE THE STRING
  359.  
  360. * Reference To: USER32.LoadStringA, Ord:0168h
  361.                                   |
  362. :00402D7C 8B1DB0734000            mov ebx, dword ptr [004073B0]
  363. :00402D82 837D1001                cmp dword ptr [ebp+10], 00000001 ; (DUMMY)
  364. :00402D86 1BFF                    sbb edi, edi                     ; (DUMMY)
  365.  
  366. * Possible Reference to String Resource ID=00056: "wordpad.exe"
  367.                                   |
  368. :00402D88 6A38                    push 00000038              ; ID TO "WORDPAD.EXE" IN THE TABLE
  369. :00402D8A FF3570514000            push dword ptr [00405170]  ; HANDLE TO THE MODULE CONTAINING
  370.                                                              ; THE TABLE
  371. :00402D90 FFD3                    call ebx                   ; CALL LOADSTRING
  372.  
  373.  
  374.  
  375. Excellent! We found our buffer...write down that memory address, and REMEMBER it, as we'll use it
  376. as a "multi-purpose" variable during our session: 63F8C4h...even if we'll
  377. overwrite it with our new string "hnotepad.hlp", the buffer will be replaced with the old string
  378. whenever the program tries to run wordpad. Notice that we can, following this method, find out
  379. the "unvariable" informations of a call as well, in this case the handle to the module
  380. containing the stringtable (the "dword ptr [405170]" pushed at 2D8A, which contains the value
  381. 400000h, that will be our handle). We could push 400000h directly when we needed, but we'll
  382. always use this pointer (remember that when you modify already compiled targets it's safe,
  383. above all for those who haven't got much experience, to verify data twice, and generally to use
  384. AS OFTEN AS POSSIBLE pointers and not immediate values), yet we'll use the immediate value later,
  385. for reasons that you will understand.
  386.  
  387. Now we know how to obtain the string "hnotepad.hlp" in our code, and where we'll find it when we
  388. need it, but yet we miss the final detail....HOW do we call the WinHelpA function? Once again
  389. our API reference helps us:
  390.  
  391. BOOL WinHelp(
  392.  
  393.     HWND hWndMain,    // handle of window requesting Help
  394.     LPCTSTR lpszHelp,    // address of directory-path string
  395.     UINT uCommand,    // type of Help
  396.     DWORD dwData     // additional data
  397.    );
  398.  
  399. Well, this is simple...once again we'll see how things really work by looking at practical
  400. examples of the function in the code: so, a BPX WinHelpA in softice will help us examine the
  401. code when we choose "Help"/"Help Topics"...
  402. there u go:
  403.  
  404. :0040121C 6A00             push 00000000 ; NO ADDITIONAL DATA
  405. :0040121E A194604000       mov eax, dword ptr [00406094] ; EAX=POINTER TO "NOTEPAD.HLP" STRING
  406. :00401223 6A0B             push 0000000B ; =HELP_FINDER, JUST A WAY TO CALL HELP
  407. :00401225 50               push eax      ; PUSHES "NOTEPAD.HLP"
  408. :00401226 FF3500604000     push dword ptr [00406000] ; HERE IS THE POINTER TO THE HANDLE OF THE
  409.                                                      ; WINDOW
  410.  
  411. * Reference To: USER32.WinHelpA, Ord:0225h
  412.                                   |
  413. :0040122C FF154C744000     Call dword ptr [0040744C] ; CALLS WINHELPA
  414.  
  415.  
  416. You may be wondering how did i know that 0Bh is equal to HELP_FINDER parameter. I suggest you
  417. download Masm32 and take a look at the file "windows.inc" under masm32\include. It contains all
  418. the equates you will need when you want to associate a literal param to a hex number (literal
  419. params are just equates to numbers, so when you code your own .ASM program you can either push
  420. the number or the literal parameter, it just makes no difference. But when it comes to patching
  421. a compiled target you HAVE to know the numeric value, or you will never know what to push).
  422. Good....now we know that the handle (which was the thing that we wanted to know the most) will
  423. be found, when needed, at the address where dword ptr [406000] points to...
  424. One last word about this function: our API reference informs us that we'll have to call
  425. WinHelpA with parameter HELP_QUIT (= 02) when we close the program, but we won't have to worry
  426. about it in our case because notepad automatically does the job for us at closing time.
  427.  
  428. Great! Now we have all the infoes we need to dive into the bytes and add code to our target!
  429. First of all, we'll change the CMP at 4011BA (@offset 5BAh) into a "JMP 40891E"
  430.  
  431. was:
  432.  
  433. :004011BA 3D00030000              cmp eax, 00000300
  434. :004011BF 7C21                    jl 004011E2
  435.  
  436. and becomes:
  437.  
  438. :004011BA E95F770000 ************ jmp 0040891E ; -> TOWARDS OUR NEW CODE
  439. :004011BF 90                      nop
  440. :004011C0 90                      nop
  441.  
  442. So we turned a CMP and a JL into a JMP and 2 NOPs. The nops are needed to fill the bytes of the
  443. jl that is useless now (we could even keep those bytes, but it's a matter of clearness...u'll
  444. find it easier to organize in this way), because we will move the whole check to the .RELOC
  445. section. One last note before adding our code. We have to keep in mind that when we execute our
  446. operations the stack and the registers must be kept intact, in other words we don't have to leave
  447. any "i-was-here" track, if u get what i mean :)
  448. We can easily do that by saving all the registers and restoring them in the end with PUSHAD and
  449. POPAD. Here's the code we'll add with HIEW at offset 591Eh (F3 then F2 to insert an asm
  450. instruction...when you find the asterisks it means that you have to exit from F2 mode and write
  451. the bytes manually, as they have been generated by SoftICE (the bytes are in the "OPCODES:"
  452. part in the comments), while when you find API calls you can read the address of the dword ptr to
  453. call within CALL D,[40xxxx]):
  454.  
  455. SIDENOTE: IN HIEW, IF YOU WANT TO WRITE "DWORD PTR [xyz]", USE "D,[xyz]", IF YOU WANT TO WRITE
  456. "BYTE PTR" USE "B" AND SO ON...GENERALLY, REFER TO OTHER INSTRUCTIONS TO FIND OUT THE WAY YOU
  457. MUST TYPE IN YOURS.
  458.  
  459.  
  460. 591Eh: cmp eax, 21    ; eax holds current item's ID. 21h = ID of our new menu ("Anub|s+Insa..")
  461.        jz 5933        ; if you clicked there, process it. 2-opcodes jump, so HIEW is OK
  462.  
  463.        cmp eax,300    ; THESE ARE THE 2 CODE LINES THAT WE REPLACED WITH THE JMP IN .TEXT
  464. ****** jl 4011E2      ; SECTION...WE RESTORE THEM HERE! ...OPCODES: 0F8CB488FFFF
  465.  
  466. ****** jmp 4011C1     ; continue with the other checks, jumping back to .TEXT
  467.                       ; OPCODES: E98E88FFFF  
  468.  
  469. 5933h: pushad                  ; saves all regs
  470.        push 20                 ; max # of chars to take from the string
  471.        push 63F8C4             ; address of the input buffer, see above
  472.        push 3a                 ; 3Ah=58 dec...this is the ID of our new string "hnotepad.hlp"
  473.        push dword ptr [405170] ; handle of module containing string resource
  474.  
  475.        call LoadStringA        ; loads 20 chars of "hnotepad.hlp" string in 63F8C4
  476.                                ; CALL D,[4073B0]
  477.  
  478.        popad                   ; restores all regs
  479.  
  480.           ; now we'll stick in parameters pushing for our customized call to WinHelpA
  481.       
  482.        push 0               ; no additional data
  483.        push 3               ; 3=HELP_INDEX, will allow us to see the help index when we open it
  484.        push 63f8c4             ; buffer containing "hnotepad.hlp"
  485.        push dword ptr [406000] ; handle of window requesting Help (see above)
  486. ****** jmp 40122c              ; come back to .TEXT section at the point where we have the
  487.                                ; WinHelpA call - OPCODES: E9CE88FFFF
  488.  
  489.  
  490. Great...now run your "new" notepad, paying attention to put a help file named "hnotepad.hlp" into
  491. the same dir where u're running it from....click on our new menu, et voila! It's done...we just
  492. added a brand new function to notepad.exe :)
  493.  
  494.  
  495.  
  496. _______________________
  497.  
  498. PHASE 2 : THE ABOUT BOX
  499. _______________________
  500.       
  501.       
  502. Here we go with phase two...why did i choose to put a new about box ?? easy...first of all,
  503. Insanity and Anub|s had to be aknowledged in the about, and then, a little bit of personal
  504. satisfaction.....:))
  505. Furthermore this procedure will teach us some new things as well, because we'll soon discover
  506. that notepad.exe HASN'T GOT a OWN about box...those lamers at Micro$oft have invented a pretty
  507. useful API function, located in shell32.dll...I'm talking about ShellAboutA. This API just
  508. creates a PREDEFINED message box, with the percentage of free resources, memory and so on (in
  509. other words notepad's about box) plus some additional info that you can specify at the moment.
  510. Needless to say, this bothers us SO MUCH that we HAVE to put our own code here :D
  511. In sice, a bpx on ShellAboutA (first load the exports from shell32.dll! You can do that with
  512. either "File/Load Exports" from SoftICE's symbol loader, or appending it to the EXP='s of your
  513. winice.dat) points us in the right direction: here's where the code for the about box starts:
  514.  
  515.  
  516. :004013D0 6A02                    push 00000002
  517. :004013D2 A170514000              mov eax, dword ptr [00405170]
  518. :004013D7 50                      push eax
  519.  
  520. * Reference To: USER32.LoadIconA, Ord:015Eh
  521.                                   |
  522. :004013D8 FF1550744000            Call dword ptr [00407450]
  523. :004013DE 50                      push eax
  524. :004013DF 683C614000              push 0040613C
  525. :004013E4 FF3560604000            push dword ptr [00406060]
  526. :004013EA FF3500604000            push dword ptr [00406000]
  527.  
  528. * Reference To: SHELL32.ShellAboutA, Ord:004Ch
  529.                                   |
  530. :004013F0 FF1580734000            Call dword ptr [00407380]
  531.       
  532.  
  533. bah, useless stuff...rather, we'll stick here the jump to .RELOC section, where our code will
  534. be.
  535.  
  536. Like in the previous situation, we must first understand WHAT we want to do. An about box,
  537. right ? Then a message box will be more than enough. Here's the prototype for this simple API
  538. function:
  539.  
  540. int MessageBox(
  541.  
  542.     HWND hWnd,            // handle of owner window
  543.     LPCTSTR lpText,    // address of TEXT in message box
  544.     LPCTSTR lpCaption,    // address of TITLE of message box 
  545.     UINT uType             // style of message box
  546.    );
  547.  
  548. Hmmm....how about those two buffers ? The text we want to stick in is quite long...we could add
  549. more strings to the stringtable and use two more buffers as the title and text of the message
  550. box, but we won't, for two reasons: first of all, when you patch a program and want to insert
  551. new things, you *MUST* try to optimize your code and make it as fast and as compact as possible
  552. (that's why i wouldn't have inserted those three nops at the end of each part of the code if i
  553. hadn't got to write a tute about all this :), and SECOND, NEVER leave unused strings...in other
  554. words, before adding new resources, you have to figure out if there are any older resources
  555. that you will not use anymore...if so, rather than adding new resources for you purposes, you'd
  556. better OVERWRITE obsolete ones...remember, SAVING SPACE IS FUNDAMENTAL!). Now let's try to
  557. figure out that in our case: in PHASE 5 of this tutorial we'll eliminate the box that says
  558. "This file is too large for Notepad to open...", as we'll remove the limit in size, so
  559. consequently we could stick our new about text in the place of that string...so the pointer to
  560. the old "This file blah blah" string (which is the one at 4060B0, as you can see breaking on
  561. the message box above) would point now to the TEXT of our about box...so everything we have to
  562. do is, in BRW, modifying the string that has ID 52, changing it from
  563.  
  564. "This file is too large for Notepad to open.\nWould you like to use WordPad to read this file?"
  565.  
  566. into
  567.  
  568. "RingZ3r0's Hnotepad v1.00\nModified version of Micro$oft's Notepad.exe\n\n\n* Code reverse engineering and implementation of new functions by -NeuRaL_NoiSE\n\n* Help file on HTML programming by Anub|s and Insanity"
  569.  
  570. You can just copy&paste the above text. Those "\n" go to next line, as in c.
  571. We still have the problem of the title. C'mon we could add this little string you say...NO ! I
  572. answer :)...we MUST learn to optimize our code (even if we get some real big quantities of
  573. redundant stuff here, but that's for "educational purposes" so don't bother asking yourself
  574. why;)...Mmh let's see...the title of the about box must be something like "Hnotepad" right ?
  575. well, now take a look at all those strings in the stringtable where the word "Notepad"
  576. appears...let's do one thing. We'll modify all those "Notepad" into "Hnotepad"....except for
  577. "notepad.hlp" of course! So, do it! :)
  578. Now make the program start, set a breakpoint somewhere and, once in the code, take a look at
  579. memory...a simple "s 0 l ffffff 'Hnotepad'" from SoftICE (or a research from hiew, if you wish to
  580. find the string physically inside the .exe) will point us to every place in memory where the
  581. string "Hnotepad" appears...once you found the first one, proceed by entering just "s" to look
  582. for the next match...now stop by the match at 41027E. You'll notice that it's preceded AND
  583. followed by 00 bytes...this means that the string is simply that, between the zero bytes...in
  584. other words, it's just "Hnotepad"...a prefect title for our message box don't you think ?? ;)
  585. We could, just as above, have pushed directly the address 41027E when we needed it (in other
  586. words when specifying the title of the MessageBoxA)...but we'll find the pointer to that
  587. buffer, and we'll push it instead of the direct memory address...the reasons are the same of
  588. above. Don't be frightened by the sound of the words, a buffer is nothing more than a variable,
  589. and a pointer.....well let's say that it's the "name" of this variable, to make it easier for
  590. everyone :). Pointers to common variables reside in .DATA section. We have already seen some
  591. pointers, do you remember ? I'm talking about the "handle of module containing string resource"
  592. we must know for the LoadStringA function, the pointer to the text of the message box, and so
  593. on....the first pointer, for example, was at 405170....this is enough for us to locate .DATA
  594. section...now everything we must do is finding a pointer (the 'name') to the buffer (of the
  595. 'variable') 41027E ("Hnotepad")...so, in SoftICE, "DD 405170" and look among the dwords...and
  596. there it is, the pointer we were looking for is at 406060.
  597. So what's left ?? Hmmm, the handle of the owner window...from a practical example (once again
  598. the "wanna load wordpad?" box), we notice that [ebp+8] contains the hwnd....and this doesn't
  599. change, as you will see if you experiment a bit...so, we have our last parametere as well, the
  600. hwnd!
  601. Now we just have to decide the style of message box...imho, being this an "about" message box,
  602. a value of 0 (=MB_OK, in other words a single button with "OK" written on it) will be perfect
  603. as style...
  604.  
  605. So now we're ready! All is left to do is modify the existing code to make it jump to our own
  606. instructions in the .RELOC section....considered those 3 NOPs, the VA where we'll append our
  607. code will be 40895E (@offset 595Eh), so we have to stick in a jump in .TEXT section to jump to
  608. it. The beginning of the ShellAboutA routine (@VA 4013D0, @offset 7D0h) will be good:
  609.  
  610. was
  611.  
  612. :004013D0 6A02                    push 00000002
  613. :004013D2 A170514000              mov eax, dword ptr [00405170]
  614.  
  615. and becomes
  616.  
  617. :004013D0 E989750000 ************ jmp 0040895E ; --> TOWARDS OUR NEW CODE
  618.  
  619.  
  620. The code that follows the new jmp will be changed in a weird way, but we don't give a damn
  621. because we don't need it anymore...the program will now continue in the .RELOC section, at
  622. offset 595Eh, with OUR own code:
  623.  
  624.        ...
  625.  
  626. 595Eh: pushad                  ; saves all regs
  627.        push 00                 ; 0 = MB_OK
  628.        push dword ptr [406060] ; pushes the pointer to "Hnotepad" as TITLE
  629.        push dword ptr [4060B0] ; pushes the pointer to new string "RingZ3r0 blabla..." as TEXT
  630.        mov esi, [ebp+8]        ; hWnd of the owner window in esi
  631.        push esi                ; pushes the handle
  632.        call MessageBoxA        ; shows the message box - CALL D,[407430]
  633.        popad                   ; restores all regs
  634. ****** jmp 4016eb              ; back to .text - OPCODES: E96E8DFFFF
  635.  
  636.        nop                     ; this part of the code ends as well (the nop is useless but keep
  637.                                ; it if u're following the procedure i'm using)
  638.       
  639.  
  640. Good! So even this one has gone...now try to make the about box pop up...u'll notice that it
  641. now shows our brand new string, plus "Hnotepad" as title...of course if you try to open a file
  642. larger than FFFFh (first dimension check) bytes you'll get a nonsense message box, because old
  643. "wanna load wordpad" string is gone...but it's just a matter of patience, we'll eliminate that
  644. box as well, as i said, in PHASE 5.
  645.  
  646.       
  647.       
  648.  
  649. ________________________________________________
  650.  
  651. PHASE 3 : ADDING MASKS TO OPENFILENAME STRUCTURE
  652. ________________________________________________
  653.  
  654.  
  655. Well...seen that this is gonna be an Html files editor, it looks clear to me that it will have
  656. to show "HTML Files", "JS Files" and "VBS Files" among the masks u get when you try to open/save
  657. as something...(well if you want the truth, i HAVE to do that or Anub|s will kill me...:))) I'm
  658. joking of course ;)))
  659.  
  660. Let's start with the "Open file" dialog box.
  661. First of all you must know that the "Open file" dialog box is a predefined dialog, that is
  662. called by a specific API function, GetOpenFileNameA, which resides in Comdlg32.dll...
  663. So, in order to work with this API, start loading the exports for this dll.
  664. Another thing you should know, is that filter strings (masks) are to be specified, together
  665. with other parameters (i suggest you read Iczelion's excellent tutorials or API reference for
  666. more details) in a structure of the OPENFILENAME type, that is pushed on the stack before the
  667. call to GetOpenFileNameA. So, the structure will contain all the data we need - the filters as
  668. well :). The filters are defined in this way (let's take for instance a text files filter):
  669. Filtername db "Text files",0,"*.txt",0,0.....<--- the second zero is not an error, but it's put
  670. if the filter is the LAST one in the list. Otherwise we'll have just one zero and, immediately
  671. after, the description of the next filter. This is all we need. We can define a new string in
  672. the stringtable, that will join it at position 59 (3Bh):
  673.  
  674.  59, "HTML Files|*.htm; *.html|JS Files|*.js|VBS Files|*.vbs"
  675.  
  676. Don't worry about that "|" between descriptions and actual filters, we just need a place to
  677. locate where we'll put a ZERO BYTE once appended the string to the filter list, so that the
  678. program will believe that there are TWO strings there ("description","|","filter"...the "|"
  679. will become a 00 byte).
  680. In Sice, BPX GetOpenFileNameA and then choose "File/Open". Sice will pop, press F12 and the
  681. dialog "Open file" will appear on your screen. Press ESC and u'll be back into sice, here:
  682.  
  683.  
  684. :004012E7 6880524000              push 00405280    ; OPENFILENAME STRUCTURE IS PUSHED....
  685. :004012EC C7058C52400080514000    mov dword ptr [0040528C], 00405180
  686. :004012F6 C7059052400030524000    mov dword ptr [00405290], 00405230
  687. :00401300 C705B452400004100000    mov dword ptr [004052B4], 00001004
  688. :0040130A 83C003                  add eax, 00000003
  689. :0040130D A3BC524000              mov dword ptr [004052BC], eax
  690.  
  691. * Reference To: comdlg32.GetOpenFileNameA, Ord:0005h
  692.                                   |
  693. :00401312 E8FA350000              Call 00404911     ; <-- .......AND HERE'S THE CALL !
  694.  
  695.  
  696. Excellent, now let's take a look at memory location 405280. Move the pointer a bit upwards,
  697. and, one or two PGUPs above, you'll notice clear tracks of the filter strings ("Text Documents
  698. *.txt" and so on). The filter strings end, as you can see, at memory location 4051A9 (with the
  699. second BYTE 00, that marks the end of the member). So, a simple LoadStringA at this address
  700. will allow us to append our brand new filter string to the filters already present. Our code,
  701. once again, will continue, down into .RELOC section, at VA 40897E (@offset 597Eh). We'll stick
  702. in the jump to our code in the place of the push at 4012E7 (@offset 6E7h), that we'll restore
  703. later.
  704.  
  705. was
  706.  
  707. :004012E7 6880524000              push 00405280
  708. :004012EC C7058C52400080514000    mov dword ptr [0040528C], 00405180
  709.  
  710. and becomes
  711.  
  712. :004012E7 E992760000 ************ jmp 0040897E ; --> TOWARDS OUR NEW CODE
  713. :004012EC C7058C52400080514000    mov dword ptr [0040528C], 00405180
  714.  
  715.  
  716. As you can notice, the following MOV isn't changed, so that we'll just come back here once
  717. we're done with the mofifications and the pushing of the structure.
  718.  
  719. Now all we must do is to modify, for the same purpose, the code relative to "Save as" dialog.
  720. This dialog is a predefined one as well, and is called with API function GetSaveFileNameA
  721. (located in comdlg32.dll as usual). We won't need big modifies, it will be enough to make the
  722. code relative to the pushing of the "Save as" structure point to the "new" code relative to
  723. "Open file" (our new code). So, a bpx on GetSaveFileNameA will help us find the point we'll
  724. modify, which happens to be 40168A (@offset A8Ah):
  725.  
  726. was
  727.  
  728. :0040168A 6880524000              push 00405280 ; pushes the structure
  729. :0040168F E86B320000              Call 004048FF ; Call GetSaveFileNameA
  730.  
  731. and becomes
  732.  
  733. :0040168A E9EF720000 ************ jmp 0040897E  ; --> TOWARDS OUR NEW CODE
  734. :0040168F E86B320000              Call 004048FF ; Call GetSaveFileNameA
  735.  
  736.  
  737.  
  738. As you can see, the following call to GetSaveFileNameA hasn't changed, so we don't need to
  739. include it into our code (we'll just jump back here once we're done).
  740.  
  741. But how will our code distinguish between a GetSaveFileNameA and a GetOpenFileNameA (a
  742. differentiation is NECESSARY, seen that we MUST know WHERE in .TEXT section to jump back once
  743. we're done with structure modifying & pushing) ??
  744. Take a look at the registers, once reached our code (or the new jumps which will bring there):
  745. when we have chosen "Open file", the value in ESI will always be 0Ah (=10 dec.), which is the
  746. menu ID of the File/Open menu item. If we have chosen "Save as", the value will always be another
  747. one, of course. So, we'll just check if ESI=Ah, and we'll jump back
  748. to the according part of .TEXT section.
  749.  
  750.  
  751. So our code will be this:
  752.  
  753.        ...
  754.  
  755. 597Eh: pushad                   ; saves all regs
  756.  
  757.        push 50                  ; max # of chars to take from the string
  758.  
  759.        push 4051A9              ; addres of input buffer (appends to existing filters)
  760.  
  761.        push 3b                  ; 3Bh=59 dec...this is the ID to our new string,
  762.                                 ; "HTML Files|*.htm; *.html|JS Files|*.js|VBS Files|*.vbs"
  763.  
  764.        push dword ptr [405170]  ; handle of module containing string resource
  765.  
  766.        call LoadStringA         ; Loads the string at 4051A9
  767.                                 ; CALL D,[4073B0]
  768.       
  769.        mov byte ptr [4051b3], 0 ; puts a ZERO BYTE where we had "|" between "HTML Files" and
  770.                                 ; "*.htm", so that the separation between description and filter
  771.                                 ; is done, and the program will belive they are 2 different
  772.                                 ; strings
  773.  
  774.        mov byte ptr [4051c1], 0 ; same as above but between "*.html" and "JS Files"
  775.      
  776.        mov byte ptr [4051ca], 0 ; same as above but between "JS Files" and "*.js"
  777.  
  778.        mov byte ptr [4051cf], 0 ; same as above but between  "*.js" and "VBS Files"
  779.  
  780.        mov byte ptr [4051d9], 0 ; same as above but between "VBS Files" and "*.vbs"
  781.  
  782.        cmp esi,0ah              ; ESI=Ah if we come from a click on "Open file"
  783.  
  784.        jnz 59c7                 ; ESI != 0ah??
  785.      
  786.        popad                    ; if not, restore all regs...
  787.      
  788.        push 405280              ; ...push the modified structure...
  789.  
  790. ****** jmp 4012ec               ; AND CONTINUE WITH THE GetOpenFileNameA PART (back to .TEXT)
  791.                                 ; OPCODES: E92589FFFF
  792.   59C7:     
  793.  
  794.        popad                    ; else if esi!=0ah, restore all regs...
  795.      
  796.        push 405280              ; ...push the modified structure...
  797.  
  798. ****** jmp 40168f               ; AND CONTINUE WITH THE GetSaveFileNameA (back to .TEXT)
  799.                                 ; OPCODES: E9BD8CFFFF
  800.  
  801.  
  802. There u go...now your "Open file" and "Save as" dialogs will show more masks.
  803.  
  804. You can even lengthen your new filter string to add more masks, but you must keep in mind that
  805. you can't exceed the memory block reserved for the structure, you can't overwrite other members
  806. of the structure, and that you must put a 00 byte between the various
  807. "description","filter","description" and so on...PLUS *TWO* ZERO BYTES AT THE END OF THE LAST
  808. FILTER.
  809.  
  810.  
  811.  
  812.  
  813. ____________________________
  814.  
  815. PHASE 4 : .INI FILE ADDITION
  816. ____________________________
  817.  
  818.  
  819. So, here we go with the (apparently) most difficult part of this tutorial. First of all let's
  820. take a look at how our .INI file will look like by default:
  821.  
  822.  
  823.  
  824. ****
  825. FILE AUTOMATICALLY GENERATED BY HNOTEPAD v1.0
  826. USE ONLY 'Y' OR 'N' IN THE 'AutoWrap' FIELD !!
  827.  
  828. -NeuRaL_NoiSE 1999
  829. ****
  830.  
  831. AutoWrap=N
  832. LastFileIs=
  833.  
  834.  
  835.  
  836.  
  837. Now we can think about how do we want to organize the code relative to this function. Obviously
  838. we'll have to write a part of code that READS the .INI at program start and one that
  839. CREATES/WRITES it at quitting time.
  840. Let's analize the READ function first:
  841.  
  842.  
  843. * At Hnotepad start, the code will have to look for a predefined file C:\Windows\Hnotepad.ini.
  844.   If this file isn't found, go on as if nothing happened.
  845.  
  846. * If it's found, read data from it and look for the first equal sign ('=') contained in it.
  847.   After this sign there will be the desired position of the WordWrapping at start. If the '='
  848.   can't be found, come back to .text without more checks and proceed by default.
  849.  
  850. * If the first '=' is found, check the letter next to it, and verify if it's 'Y', 'y', 'N' or 
  851.   'n'. If the letter does not match, come back to .text and proceed by default.
  852.  
  853. * If the letter matches a 'Y' or 'y', append the 'WordWrapping toggle' message to the process's
  854.   message queue, u'll understand later how to do it.
  855.  
  856. * If it matches 'N' or 'n', go on without sending the message.
  857.  
  858. * Check if Command Line == NULL. If the user chose a file to open, we'll have to load this one
  859.   and not the one pointed in the .INI, because of course the last one has less priority than the
  860.   file we're trying to load from command line.
  861.  
  862. * ONLY if Command Line == NULL, we'll try the last file opened pointed by the .INI. Starting
  863.   from previous position, we'll look for the next '='. After this '=', there'll be the name of
  864.   the last file opened. If the '=' can't be found, come back to .text and proceed opening a
  865.   new document (like notepad would behave in normal conditions).
  866.  
  867. * if the '=' is found, check that immediately after it there's a letter ranging from 'a' to 'z'
  868.   or from 'A' to 'Z'. This is useful to determine wheter the filename is correct or not (don't
  869.   misunderstand, we're not checking if the file exist, we're just trying to avoid loading of
  870.   files such as "7:\xyz\xyz.txt"). In other words we check if the initial char is an alphabet
  871.   letter, thus a valid identifier for a drive, and not a number or a symbol. If it's not a valid
  872.   letter, come back to .text and proceed by default.
  873.  
  874. * If we found a valid letter, proceed reading until the string that defines the filename ends:
  875.   save the initial position of the string, and then go on from there looking for a space (' ',
  876.   =20h) or a carriage return (=0Dh). If neither the first nor the second can be found, proceed
  877.   until the end of file. One thing must be cleared: when we save our default .INI, after the
  878.   second '=' there's a space (' '), that, if found in the check, indicates the end of the
  879.   filename string. If, instead, we save the .INI with the name of a file to reopen afterwards,
  880.   we'll append a CR (=0Dh), which will work like the space of before. If the user has inserted
  881.   manually the name of the last file in the .INI, there's no problem as well cuz we'll have a
  882.   third check, the one for the lenght of the file. Once we reach the EOF we'll consider FINISHED  
  883. the filename definition string.
  884.  
  885. * Once we found the end of the filename definition string, copy it directly inside the buffer
  886.   that is used to open a file when cmdline!=NULL. Notepad will automatically load the file cuz
  887.   we'll do this operation BEFORE the native check for the cmdline is done. In other words, we'll
  888.   'bruteforce' the name of a file inside the buffer that would otherwise contain only 00 bytes,
  889.   thus 'simulating' the choice by the user of a file to open from command line (as in
  890.   "notepad xyz.txt").
  891.  
  892. * At this point, we'll come back to .TEXT to normally continue with the code.
  893.  
  894.  
  895. Now we must notice one thing. To add more code, we'll have to use .RSRC section, as the space in
  896. .RELOC is almost finished. Alas there'a limitation, and this limitation resides in BRW.
  897. Obviously with the help of a little logic we'll get around it pretty easily, tho you have the
  898. right to know what we're gonna face: the limitation i'm talking about is that, everytime we
  899. modify the resources, BRW RECREATES from scratch the .RSRC section. U dig it ? All your nice
  900. additional code would be DESTROYED by a single change in any of the resources if u do it with
  901. BRW. There are severals systems to get around this, and we'll use two of them: first of all we'll
  902. put (almost) all the strings we need in the stringtable BEFORE coding our stuff in .RSRC. Then,
  903. when everything will be written, we'll have to face the problem that we'll need more strings in
  904. the fifth phase of this tute, but we'll solve this later.
  905. So, start adding these two strings to the stringtable of our target (u'll understand later why we
  906. need them):
  907.  
  908.  60, "c:\\windows\\hnotepad.ini"
  909.  61, "****\nFILE AUTOMATICALLY GENERATED BY HNOTEPAD v1.0\nUSE ONLY 'Y' OR 'N' IN THE 'AutoWrap' FIELD !!\n\n-NeuRaL_NoiSE 1999\n****\n\nAutoWrap=N\nLastFileIs= "
  910.  
  911.  
  912. Another problem we'll meet will be the lack of physical space at disposition for our bytes.
  913. Towards the end of this piece of code, you will almost have ended the space in .RSRC as well, so
  914. don't waste your time later and open ProcDump now, then edit notepad's pe and click on
  915. "sections". Once there, edit .RSRC and enlarge both raw & virtual size (safer) from 3000 to 3200
  916. bytes, and finally save the changes (only to PE header will do fine).
  917. This will give us all the space we need.
  918.  
  919. This said, i suppose that we can think about the point where to place the deviation to our .INI
  920. checking code. We have to keep in mind 2 things before doing this little research:
  921.  
  922. 1) in order to inform the program that we want Wrapping on (if that's the case), we need to
  923. simulate a click on the "Word Wrap" option. This is fairly easy, we can do it with PostMessageA
  924. or with SendMessageA. SendM. will immediately jump to the window procedure so it's not suitable
  925. for our needs, as we have to make more checks (and clean everything up) afterwards. So, we'll use
  926. PostMessageA, that simply ADDS the message to the message queue of the exectuing thread. But wait
  927. a second...in order to use PostMessageA we need a HWND (in other words a window) where to send
  928. our message!
  929. So the first thing we'll have to mind is that the EDIT control (that notepad uses at the moment)
  930. must have been ALREADY CREATED WHEN WE DEVIATE TOWARDS OUR CODE.
  931.  
  932. IMPORTANT SIDE NOTE: WHEN WE DON'T SEND ANY "WORD WRAP TOGGLE" MESSAGE, WITH AN EDIT CONTROL
  933. IT WILL BE OK, THE WRAPPING WILL BE KEPT OFF...BUT, WITH A RICHEDIT CONTROL (WHICH WE'LL 
  934. IMPLEMENT IN OUR HNOTEPAD IN THE 5TH PHASE) EVERYTHING GOES NUTS. THIS IS A BUG DUE TO THE 
  935. PROBLEMS THAT COME BECAUSE WE'RE TRYING TO MAKE A SLOPPY PROGRAM LIKE NOTEPAD INTERACT WITH A 
  936. POTENTIALLY POWERFUL CONTROL LIKE THE RICHEDIT. ANYWAY IN 2 WORDS WHAT I UNDERSTOOD FROM ALL 
  937. THIS IS : IF WE SEND *ONE* "WORDWRAP" MESSAGE AT STARTUP, THE RICHEDIT CONTROL WILL PUT WRAPPING 
  938. *ON* (EVERYTHING AS NORMAL). IF WE DO *NOT* SEND ANY MESSAGES AT STARTUP, WE'LL BE IN TROUBLE 
  939. BECAUSE EVERYTHING BECOMES MESSED (LIKE OPTION TURNED OFF, BUT WRAPPING TURNED ON). IF WE SEND 
  940. *TWO* "WORDWRAP" MESSAGES, THE PROGRAM WILL FIRST PUT WRAPPING ON, THEN RE-PUT IT OFF...THIS IS
  941. IDEAL FOR OUR PURPOSES: IF WE WANT THE WRAPPING, WE'LL SEND *ONE* MESSAGE, IF WE DON'T WANT IT,
  942. INSTEAD OF AVOIDING TO SEND IT AT ALL, WE'LL SEND *TWO* OF THE SAME "WRAP TOGGLE" MESSAGES, 
  943. AVOIDING ALL THE MESS THAT THIS ANNOYING BUG IMPLIES.
  944. CONTACT ME IF THIS IS NOT CLEAR :)
  945.  
  946. 2) BUT, if we wait too long, we could fall in the opposite mistake: the thread might have already
  947. created the edit control, but the cmdline check could have been already made too! so our second
  948. check (for the file to open pointed in the .INI) would be useless...
  949. So here's the second thing we'll have to consider: THE CHECK FOR THE COMMAND LINE MUST HAVE *NOT*
  950. BEEN MADE YET.
  951.  
  952. We can easily guess that the check for the command line happens AFTER the creation of the
  953. control, and this is real good news for us. All we must do is "catching" that fleeting moment
  954. between the two operations, and insert there all our checks.
  955.  
  956. I'd say that a good start might be that message box that says "Cannot find the xyz.xxx file...",
  957. that appears everytime we try to open a file that doesn't exist. It points us to a potential
  958. place where the control has been ALREADY created and the command line has been JUST checked.
  959.  
  960. So here is where we'll arrive with a BPX MessageBoxA:
  961.  
  962.  
  963. * Reference To: USER32.MessageBoxA, Ord:0176h
  964.                                   |
  965. :00402251 FF1530744000            Call dword ptr [00407430]
  966. :00402257 8BE5                    mov esp, ebp
  967. :00402259 5D                      pop ebp
  968. :0040225A C21400                  ret 0014
  969.  
  970.  
  971. Hmm, let's go back past the ret...
  972.  
  973.  
  974. :004028D0 E84FF9FFFF              call 00402224 ; <-- WE COME BACK FROM THIS CALL
  975. :004028D5 83F806                  cmp eax, 00000006
  976. :004028D8 7545                    jne 0040291F
  977.  
  978.  
  979. Here's the check for the key we pressed. But let's take a look at the code that comes before,
  980. what's that CreateFileA?? :)
  981.  
  982.  
  983. :00402853 803B00                  cmp byte ptr [ebx], 00
  984. :00402856 0F84F4000000            je 00402950
  985. :0040285C 53                      push ebx
  986. :0040285D 68D0524000              push 004052D0
  987. :00402862 E8F6F9FFFF              call 0040225D
  988. :00402867 6A00                    push 00000000
  989. :00402869 6880000000              push 00000080
  990.  
  991. :0040286E 6A03                    push 00000003
  992.  
  993. * Reference To: KERNEL32.CreateFileA, Ord:0039h
  994.                                   |
  995. :00402870 8B1D44734000            mov ebx, dword ptr [00407344]
  996.  
  997.  
  998. Very interesting...here we have the check that interested us, the cmd line check!!
  999. The byte ptr [ebx] contains 00 if we didn't put anything as command line, but let's try to put a
  1000. bpx on the check (at 402853), then let's get back to DOS prompt and let's type
  1001. NOTEPAD FAKE_FILE...sice will pop at 402853. Now try "D EBX"...u'll find there "FAKE_FILE", just
  1002. as you wrote it...right! this is the command line buffer! :)
  1003. but wait a sec...that's not the buffer we have to use...can u see that call next to the check?
  1004. here it is:
  1005.  
  1006. :0040285C 53                      push ebx
  1007. :0040285D 68D0524000              push 004052D0
  1008. :00402862 E8F6F9FFFF              call 0040225D
  1009.  
  1010. If you trace into it, u'll notice that this call is comparable to an lstrcpy, in other words it
  1011. COPIES the name of the file (in d,[ebx]) into the predefined buffer at 4052d0: furthermore, if in
  1012. the command line, like in our case, you have written something like FAKE_FILE, after this call
  1013. u'll notice that the name has changed into FAKE_FILE.txt -- all this call does at this point is
  1014. clear, and what we can understand is clear as well: the buffer to use is that one at 4052d0 (as
  1015. you can see even if u take a look at the params pushed before the CreateFileA that comes
  1016. afterwards). So this will be the buffer where we'll write our filename into. But there were 2
  1017. things to keep in mind, remember? We must check if the edit control has already been created at
  1018. this point. In SoftICE, once arrived at 402853, type in HWND NOTEPAD (if the name of the file
  1019. you're running is notepad.exe, or else refer to it, or find out with the TASK command); u'll
  1020. notice that the second class name is an EDIT CONTROL....bingo, it's already present, so we found
  1021. a good zone for our deviation! :)
  1022.  
  1023. We'll place the jump to our code in the place of that JE at 402856.
  1024.  
  1025.  
  1026. *** NOTE ***
  1027.  
  1028. The return addresses from our code will be several:
  1029. * if the .INI file is NOT present (or it's there but contains some errors) and the USER has NOT
  1030. chosen any file from the command line, we'll come back at 402950 (where that je would jump
  1031. normally).
  1032. * if the .INI is present but the user chose a command line, we'll come back at 40285c with that
  1033. 'Copy & Add Extension' call.
  1034. * if the .INI is present and the user did NOT choose a command line, we'll copy the filename
  1035. (pointed by the .INI) DIRECTLY INSIDE THE BUFFER AT 4052d0, and we'll come back at 402867 with
  1036. the first CreateFileA parameter pushing, that refers to that buffer.
  1037.  
  1038. ***END NOTE***
  1039.  
  1040.  
  1041.  
  1042. Our code will begin at 40BEED (@88edh) -- actually we could have saved some bytes but it's safe
  1043. this way -- thus the deviation will be this (@1c56h):
  1044.  
  1045. was
  1046.  
  1047. :00402856 0F84F4000000            je 00402950
  1048.  
  1049. and becomes
  1050.  
  1051. :00402856 E992960000 ************ jmp 0040BEED ; --> TOWARDS OUR NEW CODE
  1052. :0040285B 90                      nop
  1053.  
  1054.  
  1055. Ah, obviously we'll need some API functions...every time you find an API call in the code, just
  1056. substitute (from HIEW) call d,[dword_ptr_of_the_api].
  1057.  
  1058. here are the dd's u'll need:
  1059.  
  1060. LoadStringA:  call d,[4073b0]
  1061. _lopen:       call d,[407364]
  1062. _lread:       call d,[407368]
  1063. PostMessageA: call d,[40745c]
  1064. lstrcpyA:     call d,[40733c]
  1065. _lclose:      call d,[4072f0]
  1066.  
  1067.  
  1068.  
  1069. Now let's take a look at our code: seen that it might be quite difficult to understand the
  1070. structure with only the offsets as references, i decided to put some explicit labels (with the
  1071. relative offset in parenthesis).
  1072.  
  1073.  
  1074. Start (@88ed):
  1075.  
  1076.   pushad ; saves all regs
  1077.   push 20 ; # of chars to take from the string
  1078.   push 63f8c4 ; buffer for reception
  1079.   push 3c ; =60 dec, the ID of "c:\\windows\\hnotepad.ini"
  1080.   push 400000 ; handle of the module with the stringtable
  1081.   call LoadStringA
  1082.  
  1083.   push 0 ; pushes a dummy parameter on the stack, we'll overwrite it with the handle of the file
  1084.          ; if the .INI is found.
  1085.  
  1086.   push dword ptr [406000] ; saves the hWnd. You always find it here. You can easily find this
  1087.                           ; out by looking at the pointers in the .IDATA section. We can't use
  1088.                           ; the old [ebp+8] we used before, because this passage is yet to come
  1089.                           ; at this point.
  1090.  
  1091.  
  1092.  
  1093. ; NOW WE MUST OPEN THE FILE...WE'LL USE _lopen:
  1094. ;
  1095. ; HFILE _lopen(
  1096. ;
  1097. ;    LPCSTR lpPathName,    // pointer to name of file to open
  1098. ;    int iReadWrite     // file access mode
  1099. ;   );    
  1100.  
  1101.  
  1102.   push 0 ; = OF_READ, opens for reading only and the call fails if the file doesn't exist
  1103.   push 63f8c4 ; "c:\windows\hnotepad.ini"
  1104.   call _lopen
  1105.   cmp eax, -1 ; was there an error while opening ??
  1106.   jnz FILE_FOUND (@8924h)
  1107.  
  1108.     pop eax ; throw away the dummy param
  1109.     pop eax ; throw away the hWnd
  1110.     popad   ; restores all regs
  1111.     jmp ERROR_IN_FILE (@8a11h)
  1112.  
  1113. FILE_FOUND (@8924h):
  1114.  
  1115.   mov [esp+4], eax ; file handle in the place of the dummy param
  1116.  
  1117.  
  1118.  
  1119.  
  1120. ; NOW WE MUST READ DATA FROM THE FILE....WE'LL USE _lread:
  1121. ;
  1122. ; UINT _lread(
  1123. ;
  1124. ;     HFILE hFile,    // handle to file
  1125. ;     LPVOID lpBuffer,    // pointer to buffer for read data
  1126. ;     UINT uBytes     // length, in bytes, of data buffer
  1127. ;    );    
  1128.  
  1129.  
  1130.  
  1131.  
  1132.   push ff; # of bytes to read; ATTENTION - USE OPCODES 68FF000000, otherwise HIEW will put
  1133.          ; 6AFF, that will be interpretated by Win98 (not by 95) as PUSH FFFFFFFF, not
  1134.          ; PUSH 000000FF
  1135.   push 4109a1 ; buffer "RingZ3r0's Hnotepad.....", restored in CLOSE (@89EBh)
  1136.   push eax ; file handle
  1137.   call _lread
  1138.  
  1139.   mov edi, 4109a1 ; what we have read from the file
  1140.   mov ecx, eax ; effective lenght of the file in ecx
  1141.   mov al, 3d ; '='
  1142.   repnz scasb ; search AL ('=') in the buffer pointed by EDI for a lenght of ECX bytes
  1143.   jnz ERROR (@895Fh) ; if the '=' has not been found
  1144.  
  1145. ; if the '=' has been found, EDI points to the byte NEXT TO THE '='.
  1146.  
  1147.   mov esi, 1 ; esi will count HOW MANY TIMES WE MUST SEND THE "WRAP TOGGLE" MESSAGE -- READ THE
  1148.              ; IMPORTANT SIDENOTE OF BEFORE FOR MORE INFOES
  1149.  
  1150.   cmp byte ptr [edi], 59 ; 'Y'
  1151.   jz SEND_AUTOWRAP (@896Dh)
  1152.   cmp byte ptr [edi], 79 ; 'y'
  1153.   jz SEND_AUTOWRAP (@896Dh)
  1154.   cmp byte ptr [edi], 4E ; 'N'
  1155.   jz AUTOWRAP_OFF (@896Ch)
  1156.   cmp byte ptr [edi], 6E ; 'n'
  1157.   jz AUTOWRAP_OFF (@896Ch)
  1158.  
  1159. ERROR (@895Fh):
  1160.  
  1161.   pop eax ; scarica hWnd
  1162.   mov dword ptr [63f8c4], 40c011 ; this dword ptr will be the location containing the variable
  1163.                                  ; VA where we'll jump within our "universal" return routine,
  1164.                                  ; CLOSE (@89EBh).
  1165.                                  ; 40c011 is the VA for ERROR_IN_FILE (@8a11h)
  1166.   jmp CLOSE (@89EBh) ; = jmps in HIEW
  1167.  
  1168.  
  1169.  
  1170. AUTOWRAP_OFF (896Ch):
  1171.  
  1172.   inc esi ; esi=2 so it will send the "wrap toggle" message TWO times, switching wrapping ON and
  1173.           ; then OFF!
  1174.  
  1175.  
  1176. SEND_AUTOWRAP (@896Dh):
  1177.  
  1178.  
  1179. ; NOW WE'LL SEND THE MESSAGE RELATIVE TO THE WRAPPING, USING PostMessageA:
  1180. ;
  1181. ; BOOL PostMessage(
  1182. ;
  1183. ;     HWND hWnd,    // handle of destination window
  1184. ;     UINT Msg,      // message to post
  1185. ;     WPARAM wParam,    // first message parameter
  1186. ;     LPARAM lParam     // second message parameter
  1187. ;    );
  1188. ;
  1189. ; OBVIOUSLY WE WANT TO SIMULATE A CLICK ON A MENU ITEM: THE MESSAGE WILL THEREFORE BE 111h
  1190. ; (WM_COMMAND), AND wParam WILL BE 1Bh (=27 DEC, THE MENU ID OF "Edit/Word Wrap")
  1191.  
  1192.  
  1193.  
  1194.   pop eax ; restores hWnd....
  1195.   push eax; ...and re-saves it
  1196.   push ecx; saves the remaining bytes for the scasb of the next check, because PostMessageA
  1197.           ; modifies the ECX register
  1198.  
  1199.   push 0 ; lParam
  1200.   push 1b ; wParam
  1201.   push 111; = WM_COMMAND
  1202.   push eax ; l'hWnd
  1203.   call PostMessageA
  1204.  
  1205.   pop ecx ; restores the remaining bytes for the scasb in the next check
  1206.   dec esi ; decrease counter
  1207.   jnz SEND_AUTOWRAP (896Dh) ; jumps if esi=2, so we want the wrapping to be OFF
  1208.  
  1209.  
  1210.  
  1211.   cmp byte ptr [ebx], 0 ; check if CMDLINE==NULL
  1212.   jz CONTINUE (@8996h)
  1213.   pop eax ; throw away hWnd
  1214.   mov dword ptr [63f8c4], 40285c ; else return VA = 40285c, see "*** NOTE ***"
  1215.   jmp CLOSE (@89EBh) ; = JMPS in HIEW
  1216.  
  1217. CONTINUE (8996h):
  1218.  
  1219.   mov al, 3d ; '='
  1220.   repnz scasb ; search AL ('=') in the buffer pointed by EDI for a lenght of ECX bytes
  1221.               ; ecx, of course, has been decreased (by the previous repnz scasb) of the # of
  1222.               ; bytes between the BEGINNING of file and the FIRST '='
  1223.   jnz ERROR (@895Fh) ; if the '=' has not been found
  1224.  
  1225.  
  1226.  
  1227.  
  1228. ; NOW WE'LL CHECK IF THE CHAR IMMEDIATELY AFTER THE '=' IS A CORRECT ALPHABET LETTER. THE ASCII
  1229. ; VALUES ARE : 'a' = 61  ,   'z' = 7A  ,   'A' = 41   and    'Z' = 5A
  1230.  
  1231.  
  1232.  
  1233.   cmp byte ptr [edi], 61 ; 'a'
  1234.   jge 2_LOWCASE (@89A3h)
  1235.   jmp UPCASE (@89A8h) ; JMPS in HIEW
  1236.  
  1237. 2_LOWCASE (89A3h):
  1238.  
  1239.   cmp byte ptr [edi], 7a; 'z'
  1240.   jle OK (@89C1h)
  1241.  
  1242. UPCASE (@89A8h):
  1243.  
  1244.   cmp byte ptr [edi], 41 ; 'A'
  1245.   jge 2_UPCASE (@89AFh)
  1246.   jmp INVALID (@89B4); = JMPS in HIEW
  1247.  
  1248. 2_UPCASE (89AFh):
  1249.  
  1250.   cmp byte ptr [edi], 5a ; 'Z'
  1251.   jle OK (@89C1h)
  1252.  
  1253. INVALID(@89B4h):
  1254.  
  1255.   pop eax ; scarica l'hWnd
  1256.   mov dword ptr [63f8c4], 402950 ; return VA, see "*** NOTE ***"
  1257.   jmp CLOSE (@89EBh) ; = JMPS in HIEW
  1258.  
  1259. OK (@89C1h):
  1260.  
  1261.   push edi ; saves the position of the first byte in the filname defintion string
  1262.  
  1263.  
  1264. SEARCH_CR_OR_SPACE (@89C2):
  1265.  
  1266.       inc edi
  1267.       cmp byte ptr [edi], 20 ; ' '
  1268.       jz FOUND (@89D0h)
  1269.       cmp byte ptr [edi], 0D ; = Carriage Return
  1270.       jz FOUND (@89D0h)
  1271.       dec ecx ; ECX contains the bytes between the second '=' and EOF
  1272.       jnz SEARCH_CR_OR_SPACE (@89C2)
  1273.  
  1274. FOUND (@89D0):
  1275.  
  1276.   mov byte ptr [edi], 0 ; marks, in memory, the end of the filename definition string
  1277.   pop edi ; restores the initial position of the string (that now ends with a 00 byte)
  1278.  
  1279.   push edi
  1280.   push 4052d0
  1281.   call lstrcpyA ; copies EDI (begin name of file - zero byte) in 4052d0 (buffer for the file to
  1282.                 ; open)
  1283.  
  1284.   mov dword ptr [63f8c4], 402867 ; VA for the return jump, see "*** NOTE ***"
  1285.   pop eax ; throws away hWnd
  1286.  
  1287.  
  1288. CLOSE (@89EBh):
  1289.  
  1290.   pop eax ; file handle in eax
  1291.  
  1292.  
  1293.  
  1294. ; NOW WE HAVE TO CLOSE HNOTEPAD.INI; WE'LL USE _lclose:
  1295. ;
  1296. ; HFILE _lclose(
  1297. ;
  1298. ;     HFILE hFile     // handle to file to close
  1299. ;
  1300. ;    );    
  1301.  
  1302.  
  1303.  
  1304.   push eax ; file handle
  1305.   call _lclose
  1306.  
  1307.   push 100            --\ 
  1308.   push 4109a1           |
  1309.   push 34 ; = 52 DEC    | --> This LoadStringA restores the buffer "RingZ3r0's Hnotepad....."
  1310.   push 400000           |
  1311.   call LoadStringA    --/ 
  1312.  
  1313.   popad ; restores all regs
  1314.   jmp dword ptr [63f8c4] ; our variable return jump
  1315.  
  1316.  
  1317. ERROR_IN_FILE (@8A11h):
  1318.  
  1319.     cmp byte ptr [ebx], 0 ; il check per la CMDLINE, presente anche in .TEXT
  1320. *** jnz 40285c ; se CMDLINE!=NULL, OPCODES: 0F854268FFFF
  1321. *** jmp 402950 ; se CMDLINE==NULL, OPCODES: E93169FFFF
  1322.  
  1323.  
  1324.   NOP
  1325.   NOP ; i put them here to mark the end of this code piece.
  1326.   NOP
  1327.  
  1328.  
  1329.  
  1330.  
  1331.  
  1332. The end.....now try to edit a file C:\windows\hnotepad.ini, insert two '=' in it, and after the
  1333. first one write 'Y', while after the second one write the name (with path) of a file on your hdd.
  1334. Hnotepad will automatically use these infoes at start.
  1335.  
  1336. ---
  1337.  
  1338. Ok, but we solved only part of the problem. Let's analize now the part relative to automatic
  1339. WRITING of the .INI file every time we quit hnotepad:
  1340.  
  1341. * Before quitting, the program will create a file "C:\windows\hnotepad.ini"; if the file
  1342.   exists, it truncates its size to 0 and it recreates it; if creation fails, exit as if nothing
  1343.   happened :)
  1344.  
  1345. * If the file is created correctly, load the "skeleton" of the .INI file (seen before) into
  1346.   memory, and retrieve the necessary info to write data in it (name of the last file opened and
  1347.   Word Wrapping status at exit time).
  1348.  
  1349. * Write (in memory) all data relative to wrapping and last file, putting them in the correct
  1350.   points of the skeleton in memory.
  1351.  
  1352. * Write the skeleton along with the new data in the file
  1353.  
  1354. * Quit the program
  1355.  
  1356.  
  1357. In order to do this, obviously, we need to know these 2 things:
  1358.  
  1359. 1) WHERE we'll find the name of the last file opened before closing and
  1360. 2) WHERE we can check the present status of the Word Wrapping.
  1361.  
  1362. Good...first answer is really easy: the name is always there, into the same open-file-name
  1363. buffer, at exit time as well: 4052d0.
  1364.  
  1365. Second question is just a bit harder, but nothing serious.
  1366.  
  1367. Do you remember that main call in the window procedure ? the one that processed the messges sent
  1368. to the window? let's take another look:
  1369.  
  1370.  
  1371. * Referenced by a CALL at Address:
  1372. |:00401E58 
  1373. |
  1374. :0040116C 55                      push ebp
  1375. :0040116D 8BEC                    mov ebp, esp
  1376. :0040116F 81EC04010000            sub esp, 00000104
  1377. :00401175 33C0                    xor eax, eax
  1378. :00401177 56                      push esi
  1379. :00401178 57                      push edi
  1380. :00401179 BE38614000              mov esi, 00406138
  1381. :0040117E 8DBDFCFEFFFF            lea edi, dword ptr [ebp+FFFFFEFC]
  1382. :00401184 B940000000              mov ecx, 00000040
  1383. :00401189 A4                      movsb
  1384. :0040118A 8DBDFDFEFFFF            lea edi, dword ptr [ebp+FFFFFEFD]
  1385. :00401190 F3                      repz
  1386. :00401191 AB                      stosd
  1387. :00401192 66AB                    stosw
  1388. :00401194 AA                      stosb
  1389. :00401195 0FB7750C                movzx esi, word ptr [ebp+0C] ; <- ID VALUE OF THE CHOSEN MENU
  1390. :00401199 83FE20                  cmp esi, 00000020 ; COMPARES ID VALUE AND 20h
  1391. :0040119C 8BC6                    mov eax, esi
  1392. :0040119E 7F1A                    jg 004011BA       ; IF ID > 20h, TAKE THE JUMP
  1393. :004011A0 0F84C1030000            je 00401567
  1394. :004011A6 48                      dec eax
  1395. :004011A7 83F81B                  cmp eax, 0000001B
  1396. :004011AA 7736                    ja 004011E2
  1397. :004011AC 0FB68838174000          movzx ecx, byte ptr [eax+00401738]
  1398. :004011B3 FF248DF8164000          jmp dword ptr [4*ecx+004016F8] ; OTHERWISE PROCESS
  1399.                                                                  ; ACCORDINGLY
  1400.                                                                 
  1401. Excellent. Intuitively, our best bet is to confide in a "BPX 401199 if esi==1b" in order to
  1402. analize code behaviour in case of wrapping toggling. We'll reach the variable jmp at 11b3 and
  1403. this will redirection us towards 401491:
  1404.  
  1405.  
  1406. :00401491 833D1860400001          cmp dword ptr [00406018], 00000001 ; [406018]=0 if wrap=OFF
  1407.                                                                      ; [406018]=1 if wrap=ON
  1408. :00401498 1BC0                    sbb eax, eax
  1409. :0040149A F7D8                    neg eax
  1410. :0040149C 50                      push eax
  1411. :0040149D E8EC1E0000              call 0040338E
  1412. :004014A2 85C0                    test eax, eax
  1413. :004014A4 7415                    je 004014BB
  1414. :004014A6 833D1860400001          cmp dword ptr [00406018], 00000001
  1415. :004014AD 1BC0                    sbb eax, eax
  1416. :004014AF F7D8                    neg eax
  1417. :004014B1 A318604000              mov dword ptr [00406018], eax ; REFRESH THE PTR WITH THE NEW
  1418.                                                                 ; WRAPPING POSITION
  1419.  
  1420.  
  1421. We can easily deduct from this that the dword ptr [406018] is nothing more than a status flag, to
  1422. be more precise it's our Word Wrapping Status Flag :)
  1423. If it's 0, wrapping is OFF, and this procedure ACTIVATES it, setting the dword ptr [406018] to 1.
  1424. If it's 1, wrapping is ON, and the procedure does exactly the contrary.
  1425. At exit time, this ptr is kept, and it clearly indicates us wheter wrapping was ON or OFF when we
  1426. chose to quit, so we'll just need to check it and that's it.
  1427.  
  1428. Intuitively, the point where to jump from is the code relative to WM_DESTROY, in other words when
  1429. we have almost closed everything up and the user can't decide to cancel the quitting operation.
  1430. In order to track down the correct code zone, we'll use a fairly easy method: the API function
  1431. RegisterClass.
  1432. In the Disasm, look for "registerclass" and u'll be here:
  1433.  
  1434.  
  1435. :00402B19 C745F820604000          mov [ebp-08], 00406020
  1436. :00402B20 C745D8AD1A4000          mov [ebp-28], 00401AAD
  1437. :00402B27 C745F006000000          mov [ebp-10], 00000006
  1438. :00402B2E C745D400100000          mov [ebp-2C], 00001000
  1439. :00402B35 50                      push eax
  1440. :00402B36 897DDC                  mov dword ptr [ebp-24], edi
  1441. :00402B39 897DE0                  mov dword ptr [ebp-20], edi
  1442.  
  1443. * Reference To: USER32.RegisterClassExA, Ord:0196h
  1444.                                   |
  1445. :00402B3C FF15CC734000            Call dword ptr [004073CC]
  1446.  
  1447.  
  1448. Really easy, just take a look at the locations MOVed in [ebp-xx] before the call and you'll soon
  1449. notice that the beginning of the window procedure is at 401aad:
  1450.  
  1451. :00401AAD 55                      push ebp
  1452. :00401AAE 8BEC                    mov ebp, esp
  1453. :00401AB0 56                      push esi
  1454. :00401AB1 57                      push edi
  1455. :00401AB2 8B750C                  mov esi, dword ptr [ebp+0C]
  1456. :00401AB5 83FE05                  cmp esi, 00000005
  1457. :00401AB8 7714                    ja 00401ACE
  1458. :00401ABA 0F8406010000            je 00401BC6
  1459. :00401AC0 83FE02                  cmp esi, 00000002
  1460. :00401AC3 0F84F0000000            je 00401BB9
  1461.  
  1462. With a bpx 401ab5, you'll notice that ESI contains the message that is analized at present time.
  1463. but the one we are interested in is obviously WM_DESTROY (=02h). Good, as you can see we have a
  1464. jump at 401ac3 that will be taken only if the current message is WM_DESTROY. it'll be enough to
  1465. substitute that VA with our code starting line and the problem is gone. Our code will begin at VA
  1466. 40c022 (@8A22h), and the offset of the je to change is EC3h.
  1467.  
  1468. was
  1469.  
  1470. :00401AC3 0F84F0000000            je 00401BB9
  1471.  
  1472. and becomes
  1473.  
  1474. :00401AC3 0F8459A50000 ********** je 0040C022 ; --> TOWARDS OUR NEW CODE
  1475.  
  1476.  
  1477. The new API functions we'll need are these:
  1478.  
  1479. _lcreat:     call d,[407360]
  1480. _lwrite:     call d,[4072f8]
  1481. ExitProcess: call d,[407354]
  1482.  
  1483.  
  1484. Our code is this:
  1485.  
  1486.  
  1487. Start (@8A22h):
  1488.  
  1489.   pushad ; saves all regs
  1490.   push 20 ; # of chars to take
  1491.   push 63f8c4 ; reception buffer
  1492.   push 3c ; = 60 dec, "C:\\windows\\hnotepad.ini"
  1493.   push 400000 ; handle to the modulo with the stringtable
  1494.   call LoadStringA
  1495.  
  1496.  
  1497.  
  1498. ; NOW WE MUST CREATE THE FILE; WE'LL USE _lcreat
  1499. ;
  1500. ; HFILE _lcreat(
  1501. ;
  1502. ;     LPCSTR lpPathName,// pointer to name of file to open
  1503. ;     int iAttribute     // file attribute
  1504. ;    );
  1505. ;
  1506. ; THE ATTRIBUTE WE'LL USE WILL BE 0, OR "Normal" (THE FILE CAN BE READ OR WRITTEN TO WITHOUT  
  1507. ; RESTRICTIONS).
  1508. ; _lcreat AUTOMATICALLY TRUNCATES THE SIZE OF THE FILE TO 0 IF IT EXISTS ALREADY, OR, IF IT
  1509. ; DOESN'T EXISTS, IT CREATES THE FILE FROM SCRATCH.
  1510.  
  1511.  
  1512.   push 0      ; "Normal" attribute
  1513.   push 63f8c4 ; "C:\windows\hnotepad.ini"
  1514.   call _lcreat
  1515.  
  1516.     cmp eax, -1 ; if we had an error during creation
  1517.     jnz CREATED_OK (@8A4Fh)
  1518.     popad ; restores all regs
  1519. *** jmp 401bb9 ; where it would have jumped normally if we hadn't sticked in our deviation
  1520.                ; OPCODES : E96A5BFFFF
  1521.  
  1522. CREATED_OK (@8A4Fh):
  1523.  
  1524.   push eax ; saves file handle
  1525.  
  1526.   push 100 ; # of chars to take
  1527.   push 4109a1 ; reception buffer
  1528.   push 3d ; = 61 DEC, the ID of the "****\nFILE AUTOMATICALLY GENERATED...." string
  1529.   push 400000 ; handle to the module with the stringtable
  1530.   call LoadStringA
  1531.  
  1532.   cmp dword ptr [406018], 0 ; it's zero if WordWrapping = OFF
  1533.   jz CHECK_LASTFILE (@8A77)
  1534.   mov byte ptr [410a26], 59 ; changes the default "N" after "AutoWrap=" with "Y" (059h)
  1535.  
  1536.  
  1537. CHECK_LASTFILE (@8A77):
  1538.  
  1539.  
  1540.  
  1541. ; IN THIS CHECK WE'LL VERIFY WHETHER WE HAVE A FILENAME OR THE WORD "Untitled", WHICH MEANS THAT
  1542. ; THERE WAS NO LAST FILE OPENED.
  1543.  
  1544.  
  1545.   mov eax, 4052d0 ; the starting address of the buffer with the last file name
  1546.   cmp byte ptr [eax], 55   ; = 'U'
  1547.   jnz LASTFILE_PRESENT (@8AB3h)
  1548.   cmp byte ptr [eax+1], 6e ; = 'n'
  1549.   jnz LASTFILE_PRESENT (@8AB3h)
  1550.   cmp byte ptr [eax+2], 74 ; = 't'
  1551.   jnz LASTFILE_PRESENT (@8AB3h)
  1552.   cmp byte ptr [eax+3], 69 ; = 'i'
  1553.   jnz LASTFILE_PRESENT (@8AB3h)
  1554.   cmp byte ptr [eax+4], 74 ; = 't'
  1555.   jnz LASTFILE_PRESENT (@8AB3h)
  1556.   cmp byte ptr [eax+5], 6c ; = 'l'
  1557.   jnz LASTFILE_PRESENT (@8AB3h)
  1558.   cmp byte ptr [eax+6], 65 ; = 'e'
  1559.   jnz LASTFILE_PRESENT (@8AB3h)
  1560.   cmp byte ptr [eax+7], 64 ; = 'd'
  1561.   jnz LASTFILE_PRESENT (@8AB3h)
  1562.   cmp byte ptr [eax+8], 00 ; the zero byte that marks the end of the name
  1563.   jnz LASTFILE_PRESENT (@8AB3h)
  1564.  
  1565.   jmp WRITE_DATA (@8AC3h)  ; JMPS in HIEW
  1566.  
  1567.  
  1568. LASTFILE_PRESENT (@8AB3h):
  1569.  
  1570.   push 4052d0 ; last file name
  1571.   push 410a33 ; buffer that begins immediately after the second '=' in the skeleton which is
  1572.               ; already in memory
  1573.   call lstrcpyA
  1574.  
  1575. WRITE_DATA (@8AC3h):
  1576.  
  1577.   pop eax ; restores file handle in eax...
  1578.   push eax; ...and re-saves it
  1579.  
  1580.  
  1581.  
  1582. ; NOW WE'LL WRITE THE SKELETON TO THE FILE. WE'LL USE _lwrite, BUT THERE'S A PROBLEM. ON MY PC,
  1583. ; DUE TO YET UNKNOWN REASONS I CAN'T SAVE MORE THAN 7Fh BYTES PER TIME, AND CONSIDERED THAT THE
  1584. ; TEXT WE WANT TO SAVE IS 92h BYTES LONG, WE'LL USE _lwrite 2 TIMES, THE FIRST ONE WITH THE
  1585. ; FIRST 7Fh BYTES, THE SECOND ONE WITH THE REMAINING 13h.
  1586. ;
  1587. ; UINT _lwrite(
  1588. ;
  1589. ;     HFILE hFile,    // handle to file
  1590. ;     LPCSTR lpBuffer,    // pointer to buffer for data to be written
  1591. ;     UINT uBytes     // number of bytes to write
  1592. ;    );
  1593.  
  1594.  
  1595.  
  1596.   push 7f ; the first 7fh bytes of the skeleton
  1597.   push 4109a1 ; beginning of the skeleton buffer in memory
  1598.   push eax ; file handle
  1599.   call _lwrite
  1600.  
  1601.   pop eax ; restores file handle in eax...
  1602.   push eax; ...and re-saves it
  1603.  
  1604.   push 13 ; the remaining 13h bytes of the skeleton
  1605.   push 410a20 ; memory location where the remaining 13 bytes of the skeleton start
  1606.   push eax ; file handle
  1607.   call _lwrite
  1608.  
  1609.  
  1610. ; NOW WE MUST CHECK THE LENGHT OF THE NAME OF THE FILE, PUSH THOSE BYTES AND APPEND THAT NAME
  1611. ; TO OUR .INI FILE
  1612.  
  1613.  
  1614.   xor eax, eax ; resets counter for filename lenght
  1615.   mov edi, 410a33 ; location with the first letter of the filename
  1616.  
  1617. CHECK_LASTFILE_NAME_LENGHT (@8AEAh):
  1618.  
  1619.   cmp byte ptr [edi], 0
  1620.   jz ENDCHECK (@8AF3h)
  1621.   inc edi
  1622.   inc eax
  1623.   jmp CHECK_LASTFILE_NAME_LENGHT (@8AEAh); JMPS in HIEW
  1624.  
  1625. ENDCHECK (@8AF3h):
  1626.  
  1627.   mov byte ptr [edi], 0d ; appends a CR (carriage return) to the string
  1628.   inc eax
  1629.   pop edi ; file handle in edi
  1630.   push eax ; # of bytes to write
  1631.   push 410a33 ; where filname begins
  1632.   push edi ; file handle
  1633.   call _lwrite
  1634.  
  1635.   push edi ; file handle
  1636.   call _lclose
  1637.  
  1638.   popad ; restores all regs
  1639.  
  1640.   call ExitProcess ; quit the program
  1641.  
  1642.   NOP
  1643.   NOP ; end of this part of code
  1644.   NOP
  1645.  
  1646.  
  1647. There would be something to explain here. Why did i stick in a direct call to ExitProcess without
  1648. allowing the program to execute the PostQuitMessage (in order to exit in a more 'clean' way)? The
  1649. problem is easy...if you try to exit under certain conditions (in our case choosing anything else
  1650. than File/Exit) you'll get a fault. The reason is still unknown to me, yet i suspect it might be
  1651. due to stack trashing following some LoadStringA, and the fault happens while tracing through
  1652. kernel code. Anyway, the call to ExitProcess doesn't cause any problems, it's just a "quicker"
  1653. way to quit the process. Processing WM_CLOSE instead of WM_DESTROY doesn't give much different
  1654. results.
  1655.  
  1656.  
  1657. From now on, everytime you exit and reopen Hnotepad, the last file (if present) and the Word
  1658. Wrapping will be restored. Isn't that nice :)
  1659.  
  1660.  
  1661.  
  1662.  
  1663. __________________________________________________________________
  1664.  
  1665. PHASE 5 : ELIMINATION OF THE LIMIT IN THE SIZE OF THE OPENED FILES
  1666. __________________________________________________________________
  1667.  
  1668.  
  1669. Here we go with the fifth and last part of the creation of Hnotepad, the elimination of the limit
  1670. in the size of the files opened with Notepad.
  1671. What we'll do is fairly easy: we'll change the Edit control (which Notepad currently uses) into a
  1672. RichEdit control, the one used by WordPad.
  1673. If you want more infos on this subject, i suggest looking at you API reference and looking for
  1674. "RichEdit".
  1675.  
  1676. The thing would be really easy, if it wasn't for a single detail: in order to use a RichEdit
  1677. control, we need the Riched32.dll library to be present in memory at runtime. And in order to
  1678. load the Riched32.dll library we need the LoadLibraryA API function. But, alas (or luckily,
  1679. because we'll have some fun;), Notepad doesn't include this function among the imported ones (you
  1680. can check it with W32Dasm under Imported Functions, or with HIEW taking a look at the .IDATA
  1681. section)...this is not a big problem, we could stick in a GetProcAddress instead of another
  1682. function in the iat (GetTimeFormatA for example) and use this API in order to retreive the
  1683. address of the KERNEL32!LoadLibraryA function dynamically, at runtime...but we'll do it
  1684. differently: we'll use a piece of code written for a virus by Jacky Qwerty, a virii programmer
  1685. from one of the best virii writers groups on the scene (29A), which executes an operation exactly
  1686. identical to GetProcAddress: infact it scans the requested library in memory (in our case
  1687. Kernel32.dll) and retrieves the address of the desired function (in our case LoadLibraryA). I
  1688. won't discuss more what the code does, as (if you're lucky:) you might find somewhere a link to a
  1689. zip file containing Hnotepad.exe, this tute, and an archive i called SCANNING_CODE.ZIP, where you
  1690. can find, along with the needed include files, the commented source code for this scanning
  1691. function (KBASE.ASM) and the file i called COMPILED_SCANNING_CODE, containing the already
  1692. compiled code, that you can copy & paste inside your own targets (anywhere in the .exe, because
  1693. all the jumps are relative to its own offsets, and being a procedure to be called, the only
  1694. return point is marked by a ret). The function accepts 2 parameters, the HANDLE to the library
  1695. (or, better, the address where the library begins), in our case kernel32.dll, and the NAME of the
  1696. desired function we want to retrieve (LoadLibraryA for us). In order to copy and paste the hex
  1697. bytes inside your alien target, you can use a program like UltraEdit32 or Hex Workshop, just act
  1698. like if it was plain text (be careful to paste at the right offsets ;).
  1699.  
  1700. If there's something you don't understand in the way you should apply this code to targets, take
  1701. a look at part 4 of this tute to see how you can contact me.
  1702.  
  1703. But let's see how this system will work in OUR case: so here's the little problem i was talking
  1704. before: we'll need some variables (3 to be precise), but we can't modify the stringtable for our
  1705. purposes, because the minimal change would destroy our own work in .RSRC section. How to do then?
  1706. Easy: we'll write our variables DIRECTLY in the physical file, in a place we don't need (towards
  1707. the end of the file). But let's proceed gradually.
  1708.  
  1709. First of all we need to load the riched32.dll library and after that we'll need to change "EDIT"
  1710. into "RICHEDIT" at the right place in order to obtain an edit control that supports big files.
  1711.  
  1712. So, let's start tracing from the entry point:
  1713.  
  1714. :00401000 55                      push ebp
  1715. :00401001 8BEC                    mov ebp, esp
  1716. :00401003 83EC44                  sub esp, 00000044
  1717. :00401006 56                      push esi
  1718.  
  1719. * Reference To: KERNEL32.GetCommandLineA, Ord:00BCh
  1720.                                   |
  1721. :00401007 FF1548734000            Call dword ptr [00407348]
  1722. :0040100D 8BF0                    mov esi, eax
  1723. :0040100F 8A00                    mov al, byte ptr [eax]
  1724. :00401011 3C22                    cmp al, 22
  1725. :00401013 7513                    jne 00401028
  1726.  
  1727.  
  1728. Our deviation will be at the line next to the GetCommandLineA call, the "mov esi, eax" at 40100d
  1729. (@40Dh). Our code, included those previous NOPs, will begin at 40c116 (@8B16).
  1730. So here's the change we'll do:
  1731.  
  1732. was
  1733.  
  1734. :0040100D 8BF0                    mov esi, eax
  1735. :0040100F 8A00                    mov al, byte ptr [eax]
  1736. :00401011 3C22                    cmp al, 22
  1737. :00401013 7513                    jne 00401028
  1738.  
  1739. and becomes
  1740.  
  1741. :0040100D E904B10000 ************ jmp 0040C116 ; --> TOWARDS OUR NEW CODE
  1742. :00401012 90                      nop
  1743. :00401013 7513                    jne 00401028
  1744.  
  1745.  
  1746. We'll have to remember to restore the 3 instructions we have replaced before returning back to
  1747. .text with the jne at 401013.
  1748.  
  1749. Now we have the problem of the variables. Let's leave a bit of free space in the .RSRC section,
  1750. and let's write in there the vars we need. Consider that we'll have to stick in the scanning
  1751. code, so, given a good margin, change to HEX mode in HIEW and go to offset 8BD0h, then edit the
  1752. asciis and write:
  1753.  
  1754. LoadLibraryA
  1755.  
  1756. This will be our first variable. Then go to offset 8BE0h and write:
  1757.  
  1758. Riched32.dll
  1759.  
  1760. Here's our second variable. We'll alse need Kernel32.dll, but as you can imagine this variable is
  1761. already present in our code, in the .IDATA section: a search from HIEW will make us reach
  1762. directly this section, and among the names of the imported dll's you'll also find Kernel32.dll.
  1763. The VA is 4076E0. We can now trace a little scheme of the variables we have at our disposition,
  1764. so here are the VA's that interest us (the ones we'll use in order to refer to the variables from
  1765. the code):
  1766.  
  1767. LoadLibraryA = 40C1D0 (@8BD0h)
  1768. Riched32.dll = 40C1E0 (@8BE0h)
  1769. KERNEL32.DLL = 4076E0 (@48E0h)
  1770.  
  1771.  
  1772. Furthermore, we'll use a new API, which is
  1773.  
  1774. GetModuleHandleA = call d,[40735c]
  1775.  
  1776. it will provide us the HANDLE to the library KERNEL32.DLL, which we'll scan looking for our API
  1777. LoadLibraryA. There's a thing to say here: what is returned in EAX by this function
  1778. (GetModuleHandleA), in reality, is the BASE ADDRESS of the interested module, in other words the
  1779. address where, in memory, the library begins. This is not said in your API reference :)
  1780.  
  1781. And here's the code we'll add to load the library:
  1782.  
  1783.  
  1784. Start (@8B16):
  1785.  
  1786.   pushad ; saves all regs
  1787.  
  1788.   push 4076e0 ; "KERNEL32.DLL"
  1789.   call GetModuleHandleA ; retrieves the handle to (base address of) of the Kernel32.dll library
  1790.  
  1791.   push 40c1d0 ; "LoadLibraryA"
  1792.   push eax ; handle to (beginning address of) of KERNEL32.DLL
  1793. * call SCANNING_CODE (@8B40); THE CALL TO THE SCANNING CODE : OPCODES E813000000
  1794.  
  1795. ; IMPORTANT: THE SCANNING CODE WILL RETURN THE ADDRESS OF THE DESIRED API, BUT IN *ECX*, NOT IN
  1796. ; EAX
  1797.  
  1798.   push 40c1e0 ; "Riched32.dll"
  1799.   call ecx    ; CALL THE LoadLibraryA FUNCTION
  1800.  
  1801.   popad ; restores all regs
  1802.  
  1803.   mov esi, eax  --\
  1804.   mov al, [eax]   |____ Here we restore the code we modified in .TEXT with our JMP
  1805.   cmp al, 22      |     OPCODES FOR THE JMP : E9D34EFFFF
  1806.   jmp 401013    --/
  1807.  
  1808. SCANNING_CODE (@8B40):
  1809.  
  1810.   ; HERE YOU MUST SIMPLY PASTE THE CODE I PROVIDED IN THE FILE COMPILED_SCANNING_CODE. FOR A
  1811.   ; DETAILED DESCRIPTION OF ITS FUNCTIONS TAKE A LOOK AT AUTHOR'S COMMENTS IN THE SOURCE CODE
  1812.   ; (KBASE.ASM, INSIDE ARCHIVE SCANNING_CODE.ZIP)
  1813.  
  1814.  
  1815. Excellent, now our code is ready...we just have one more problem..we must create the control in
  1816. RichEdit mode, not Edit, or all those changes are useless. In order to modify the control, we
  1817. have to find the CreateWindowExA call (that notepad uses) that is called with the string "Edit"
  1818. pushed on the stack, and redirect that push towards our new variable "RichEdit". First of all,
  1819. let's create this variable. In HEX mode as usual, from HIEW edit the ascii at offset 8BF0, and
  1820. write
  1821.  
  1822. RichEdit
  1823.  
  1824. So the VA for this new var is 40C1F0.
  1825.  
  1826. In order to find the call we are interested in, from sice "BPX CreateWindowExA" and run notepad.
  1827. You'll arrive to this point:
  1828.  
  1829. :00402785 53                      push ebx
  1830. :00402786 A100604000              mov eax, dword ptr [00406000]
  1831. :0040278B 56                      push esi
  1832. :0040278C 6A0F                    push 0000000F
  1833. :0040278E 50                      push eax
  1834. :0040278F 6890010000              push 00000190
  1835. :00402794 6858020000              push 00000258
  1836. :00402799 53                      push ebx
  1837. :0040279A 53                      push ebx
  1838. :0040279B 6804013050              push 50300104
  1839. :004027A0 688C614000              push 0040618C
  1840.  
  1841. * Possible StringData Ref from Data Obj ->"Edit"
  1842.                                   |
  1843. :004027A5 6890614000              push 00406190
  1844. :004027AA 6800020000              push 00000200
  1845. :004027AF FFD7                    call edi ; CALLS CreateWindowExA
  1846.  
  1847. Good....it's easy to guess what the change will be...at offset 1BA5h:
  1848.  
  1849. was
  1850.  
  1851. :004027A5 6890614000              push 00406190 ; "Edit"
  1852.  
  1853. and becomes
  1854.  
  1855. :004027A5 68F0C14000              push 0040C1F0 ; "RichEdit"
  1856.  
  1857.  
  1858. Now we just have TWO more details to modify, and then we can finally close this incredibly long
  1859. tutorial :)
  1860.  
  1861. 1) If you try to open big files, you'll still have the nag that asks you if you want to run
  1862. WordPad: bpx MessageBoxA, and you'll climb back to the check of the size, which is
  1863.  
  1864. :00402E8B 81FEFFFF0000            cmp esi, 0000FFFF
  1865. :00402E91 0F8FEC010000            jg 00403083
  1866.  
  1867. Just NOP that jg out (@2291h) and the problem will go away.
  1868.  
  1869.  
  1870. 2) If you open a big file and you try to insert (or you have already inserted) the Word Wrapping,
  1871. you'll notice an annoying nag that says something like "cannot carry out the wrapping because
  1872. there's too much text in the file...." and blah blah, just BPX MessageBoxA and you'll climb back
  1873. here:
  1874.  
  1875. :004014A2 85C0                    test eax, eax
  1876. :004014A4 7415                    je 004014BB ; EVIL JUMP
  1877. :004014A6 833D1860400001          cmp dword ptr [00406018], 00000001
  1878.  
  1879. Avoiding that jump (@8A4h) you'll avoid the NAG as well. So NOP it out.
  1880.  
  1881.  
  1882. Woooh.....THE END!!!! :D
  1883.  
  1884.  
  1885.  
  1886.  
  1887. _________________________________________________
  1888.  
  1889. PART 4 : Known Bugs and how to contact the author
  1890. _________________________________________________
  1891.  
  1892.  
  1893. I hope to fix them in the next versions of Hnotepad, anyway the bugs I know so far are two:
  1894.  
  1895. * WHEN YOU CLOSE A FILE, YOU ALWAYS GET THE DIALOG "WANNA SAVE THE FILE?", EVEN IF YOU DIDN'T
  1896.   EVEN TOUCH IT. THE MOST ANNOYING, DECISELY, AND I SUSPECT IT'S TIED TO THE RICHEDIT CONTROL.
  1897.   ANY HELP IS WELCOME.
  1898.  
  1899. * SOMETIMES, OPENING A BIG FILE WHEN YOU ARE *ALREADY* INTO HNOTEPAD WILL MAKE THE OLD "WANNA
  1900.   LOAD WORDPAD" NAG POP UP, EVEN IF YOU'RE WORKING WITH THE RICHEDIT AND NOT WITH THE EDIT. 99%
  1901.   IT'S A SECOND CHECK ON THE LENGHT OF THE FILE, THO I COULDN'T TRACK IT DOWN YET, I HAD SOME  
  1902.   PROBLEMS WITH UNIVERISTY, MY TIME AND MY LAZINESS ;)
  1903.  
  1904. If you happen to find some other bug, please contact me. You can do it either via email
  1905. (neural_noise@hotmail.com) or looking for me on IRC. I'm often in #cracking4newbies (EFnet) and
  1906. my nickname is NeuRaL_N. If u're sending an email, please specify which operating system you're
  1907. using.
  1908.  
  1909.  
  1910.  
  1911. __________________
  1912.  
  1913. PART 5 : Greetings
  1914. __________________
  1915.  
  1916.  
  1917. So this is the end....this tutorial is dedicated to (no particular order):
  1918.  
  1919. GEnius, for having contributed a LOT with his moral support and his ideas about RichEdit, with
  1920. his precious help as beta tester, and for having provided me the scanning code. Without him all
  1921. this wouldn't have been possible, so THANK YOU GENIUS :)
  1922.  
  1923. Kill3xx, for having been a patient beta tester, and being a good friend and a neverending well of
  1924. knowledge...excellent work with the Pesentry killo! :)
  1925.  
  1926. d4eMoN (aka Patr1zia ;P), for his help and his kindness, and for being a good friend...thanx
  1927. MONSTAH :)
  1928.  
  1929. {Suby}, for being a old friend and for his help as beta tester. Won't forget that, man :)
  1930.  
  1931. BrahzVooZ, for being the person that studies the more among the ones i know, and for being a dear
  1932. 'live' friend...COME BACK TO CRACKING BRO!! :)
  1933.  
  1934. Anub|s, for having liked the Hnotepad project at first sight, and for being a good friend.
  1935.  
  1936. Insanity (not insa|nity :), for being a big fella and the nicest web/botmaster ever :)
  1937.  
  1938. +MaLaTTiA, for being a great friend and the moderator of the most inactive mailing list of the
  1939. universe :)....and because he will be so kind that he will post me those infoes on steganography
  1940. he promised some time ago as soon as he reads this text...isn't that true, mala??? ;))
  1941.  
  1942. ytc, one of my dearest internet friends, he's a great dude and keeps telling me that i should
  1943. send my tutes to Fravia...but damn, i don't think they're worth :)...anyway thanks for everything
  1944. bro, and congrats for that beautiful unpacking program (it's growing up real l33to;) Hope to see
  1945. a tute on mem patching from you very soon ;)
  1946.  
  1947. Tin, great friend from #c4n, hope to see you soon in Italy, and bring the GIRLZ huh!! ;)
  1948.  
  1949. Carpathia, another great friend from #c4n...real l33t0, fantastic page about lamer logs
  1950. (http://lamerlogs.cjb.net) and a beta tester too, thx for everything mate :)
  1951.  
  1952. DEZM, keep on learning and you'll soon kick all those so-called crackers in the arse ;))
  1953.  
  1954. +yoshi aka _y aka yman, 15 yrs (YEAHS;) old whiny bitch with a big attitude against italians ;))
  1955. j/k of course, a real good boy, and an incredibly clever person imho (and nah i don't wanna have
  1956. sex with you :)
  1957.  
  1958. Fravia+, the BIG one, the best reverser at the moment imho.
  1959.  
  1960. +ORC, the legend, the myth...another real BIG one, the reason why all crackers are so proud of 
  1961. their past :)
  1962.  
  1963. Guybrush (^__^ ;), Quequero, N6U5, Furb3t, courier^, guiz, Corn, Crackz, Ghiribizzo, Iczelion,
  1964. sortof, Alor, Along3x, Yan Orel and all the other friends from #crack-it, #cracking4newbies and
  1965. RingZ3r0 that i don't remember at the moment :)
  1966.  
  1967. TURN OFF YOUR PC AND GO TO SLEEP NOW :D
  1968.  
  1969. 'till next time,
  1970.  
  1971. -NeuRaL_NoiSE 1999 for RingZ3r0, absolutely the BEST CRACKING AND REVERSE ENGINEERING SITE IN
  1972. ITALY! (http://ringzer0.cjb.net)
  1973.