home *** CD-ROM | disk | FTP | other *** search
/ KeyGen Studio 2002 / KeyGen_Studio_2002.iso / Tutorials / ReverseMes / dracon.txt < prev    next >
Encoding:
Text File  |  2001-09-21  |  27.6 KB  |  668 lines

  1. Solution to douby's ReverseMe 1
  2. by Dracon (DREAD)
  3.  
  4. Tools used:
  5. -----------
  6. * IDA 3.85 (Disassembler)
  7. * HIEW (hexeditor which can generate Opcodes)
  8. * SoftIce (to debug my new code)
  9. * Win32 Api reference
  10. * alphabetic list of important Api constants (very handy)
  11.  
  12. Also usefull are:
  13. * SAdd (add new sections of any size to an exe)
  14. * ProcDump (has an integrated PE-Editor)
  15. * OpGen (Opcode Generator to create the opcodes for jumps from one virtual
  16.   address to another AND it can retrieve the addresses of all imported
  17.   windows-functions)
  18.  
  19. First of all I must say that douby's idea of a "ReverseMe" is great. Adding new
  20. functions this way makes your best tools and programs even better. It's not easy
  21. though. You must know something about the PE file-format and of course win32asm.
  22. I also recommend that you read the essay about adding functions to Notepad by
  23. NeuRaL_NoiSE.
  24.  
  25. The challenge was (sorted, easiest first):
  26. 1) Add a scrollbar to the editbox
  27. 2) Add the exit option to the program
  28. 3) Add the loading option to the program
  29. 4) Add the saving option to the program (easy if you solved #3)
  30.  
  31. Let's start!
  32.  
  33. 1. Scrollbar
  34. ============
  35.  
  36. This one is easy. CreateWindowEx or CreateWindow are used to create an edit
  37. control, the one used in the ReverseMe. This is the snippet from IDA (in WDasm
  38. it looks the same, but without the ".text:", only the address is shown):
  39.  
  40. .text:0040116D                 mov     edx, [esp+8+HWND] ; move HWND to edx
  41. .text:00401171                 push    0               ; pointer to some data
  42. .text:00401173                 mov     ecx, [eax+4]
  43. .text:00401176                 push    ecx             ; hInstance
  44. .text:00401177                 push    1               ; child ID
  45. .text:00401179                 push    edx             ; parent window
  46. .text:0040117A                 push    0               ; initial height
  47. .text:0040117C                 push    0               ; initial width
  48. .text:0040117E                 push    0               ; initial y position
  49. .text:00401180                 push    0               ; initial x position
  50. .text:00401182                 push    508000C4h       ; window style !!!
  51. .text:00401187                 push    0               ; window name
  52. .text:00401189                 push    offset aEdit    ; "EDIT" - class name
  53. .text:0040118E                 push    0               ; extended styles
  54. .text:00401190                 call    ds:CreateWindowExA ; Create the window
  55.  
  56. Remember, all parameters are pushed in reverse order, the last one first. To get
  57. the scrollbars we must modify the style parameter - all styles are combined by a
  58. logical OR. I have already looked up the values for WS_HSCROLL (0x100000) and
  59. WS_VSCROLL (0x200000) for you, so we calculate:
  60.  
  61. 0x508000C4 OR 0x100000 OR 0x200000 = 50B000C4
  62.  
  63. file-offset 0x1182:        68 C4 00 80 50
  64. change to:                 68 C4 00 B0 50
  65.  
  66. Short test, okay, works. ;-)
  67.  
  68. All constants can be found in the include files (win32.inc, user32.inc, ...) and
  69. someone has created html-pages with all important constants in alphabetic order
  70. which is VERY handy.
  71.  
  72. 2. Exit menu entry
  73. ==================
  74.  
  75. Now it's getting more difficult. If you click on a menu-entry the program will
  76. get a WM_COMMAND message with the id in the low-order word of WPARAM.
  77. Fortunately, douby decided to show us a messagebox "Nope, doesn't work yet!".
  78. Fine. Look for this error string and examine the code above it. I have already
  79. renamed some of the location and variables to make the code clearer. Other
  80. comments are inserted by IDA, e.g. for the switch jump:
  81.  
  82. .text:004011CE WM_COMMAND_msg:                       ; CODE XREF: WindowProc+12
  83. .text:004011CE                 cmp     esi, 7
  84. .text:004011D1                 jz      short WM_SETFOCUS_msg
  85. .text:004011D3                 cmp     esi, 111h                  
  86. .text:004011D9                 jnz     short DEFAULT_msg ; default
  87. .text:004011DB                 push    edi            
  88. .text:004011DC                 call    ds:GetMenu      ; Get the handle of the
  89.                                                        ; menu assigned to the
  90.                                                        ; given window
  91. .text:004011E2                 mov     eax, ebx    
  92. .text:004011E4                 and     eax, 0FFFFh    
  93. .text:004011E9                 add     eax, 0FFFF63BFh ; switch 5 cases
  94. .text:004011EE                 cmp     eax, 4
  95. .text:004011F1                 ja      short DEFAULT_msg ; default
  96.  
  97.              ; ----> Important <----
  98. .text:004011F3                 jmp     ds:off_0_401260[eax*4] ; switch jump for
  99.                                                        ; Command IDs
  100.  
  101. .text:004011FA loc_0_4011FA:                           ; case 0x9c41
  102. .text:004011FA                 push    0
  103. .text:004011FC                 push    offset a3rr0r   ; "3rr0r!"
  104. .text:00401201                 push    offset aNopeDoesnTWork ; "Nope doesn't
  105.                                                        ; work yet"
  106. .text:00401206                 push    edi
  107. .text:00401207                 call    ds:MessageBoxA
  108. .text:0040120D                 pop     edi
  109. .text:0040120E                 pop     esi
  110. .text:0040120F                 xor     eax, eax
  111. .text:00401211                 pop     ebx
  112. .text:00401212                 retn    10h
  113.  
  114. Look at the line that I have marked. The next jump depends on the ID, here is
  115. the table for it (at location 401260):
  116.  
  117. .text:00401260                 dd offset loc_0_4011FA  ; IDM_LOAD
  118. .text:00401260                 dd offset DEFAULT_msg   ; default
  119. .text:00401260                 dd offset loc_0_4011FA  ; IDM_EXIT
  120. .text:00401260                 dd offset IDM_ABOUT     ; IDM_ABOUT
  121. .text:00401260                 dd offset loc_0_4011FA  ; IDM_SAVE
  122.  
  123. As you can see, 3 jumps go back (4011FA) and display our messagebox, one shows
  124. the Aboutbox and one jumps to DefWinProc. Okay, how can we know WHICH number
  125. belongs to the different IDs? I have already done the whole work for you: you
  126. can modify the jump table in that way that only ONE value will show the error
  127. message (0x4011FA), all others are set do DEFAULT_msg (0x403712). Run the
  128. program and click on the menu items. When you see the messagebox you know which
  129. entry in the jump table belongs to it. Got the idea? Good. Another approach
  130. would be to open the program with BRW (Borland Resource Workshop) and to examine
  131. the menu. The IDs should be right in front of you.
  132.  
  133. Now you know when the user chooses "Exit" from the menu. How you exit a program?
  134. Very easy, you call PostQuitMessage(0). You could now add some code to do this,
  135. but wait a moment. There should already be a call to this function somewhere.
  136. Found it?
  137.  
  138. .text:00401159                 push    0
  139. .text:0040115B                 call    ds:PostQuitMessage
  140. .text:00401161                 pop     edi
  141. .text:00401162                 pop     esi
  142. .text:00401163                 xor     eax, eax
  143. .text:00401165                 pop     ebx
  144. .text:00401166                 retn    10h
  145.  
  146. Fine, we store now this offset in the jumptable (3rd entry, file-offset 0x1268):
  147. FA 11 40 00 -----> 59 11 40 00
  148.  
  149. I hope you know why to store the address this way. On all Intel computers, words
  150. and dwords will be stored with the lowest byte first:
  151. 00 40 11 59 -> 59 11 40 00.
  152.  
  153. That's how these values are read and written from and to memory.
  154.  
  155. Test it, and it works!
  156.  
  157.  
  158. 3. File loading
  159. ===============
  160.  
  161. Now we get to the tricky parts. A filedialog should prompt the user for a file
  162. which will then be loaded. The problem is, the necessary API functions aren't
  163. included yet. We will use "GetProcAddress" to get the address of these functions
  164. at runtime. If the dll is already loaded (e.g. kernel32.dll for File I/O) you
  165. can use "GetFileModuleHandleA" to retrieve the handle. If the dll is NOT loaded
  166. (comdlg32.dll for the common dialogs) you will need "LoadLibraryA".
  167.  
  168. An important question: where do we add our code?
  169.  
  170. The (executable) code is in the "text" section of the file. Use a tool like IDA,
  171. PE-Browser or ProcDump to check it: Virtual Size = 0x2B3E, Section Size in File:
  172. 0x3000. What does this mean? Only 0x2B3E bytes are needed for the code, but
  173. 0x3000 bytes are reserved because of the alignment setting. Set the Virtual Size
  174. to 0x3000 and you have 0x4C2 (1218) bytes for your code. This should be more
  175. than enough! How do you change this value? Open the file with a hexeditor and
  176. look for "text" (offset 0x1C9). Read a good doc about the PE file header to find
  177. out more (Microsoft, Iczelion). The first 8 chars are reserved for the name of a
  178. section, after that follows the virtual size (WORD) - change it from 3E2B to
  179. 0030.
  180.  
  181. Some more explanation:
  182. ProcDump is a very good tool which can modify an exe-file in different ways. It 
  183. can change the pe-header for you. Run ProcDump, click on "PE Editor" and choose 
  184. the ReverseMe. We are interested in the "Sections". You will get a list of all 
  185. sections and you can right-click to edit them. The code is in the text-section. 
  186. Two values are important: the virtual and the physical size. The physical size 
  187. depends on the file alignment setting (Visual C++ uses 1000h, but it can be any 
  188. multiply of 200h), the virtual size tells how much space is needed for the code 
  189. and is important for the Windows PE-loader which loads the exe into memory and 
  190. executes the code. If we set the virtual size to the physical one we can use the 
  191. unused bytes for our purpose: in our case the virtual size is 0x2B3E and we can 
  192. use the bytes from 0x2B40 (to have a rememberable value) to 0x2FFF (at 0x3000 
  193. starts the next section) for our code.
  194.  
  195. 1218 bytes are really a lot, but often you will have less, maybe too less. In
  196. this case you will need the program "SAdd" by NeuRaL_NoiSE. It creates, appends
  197. and zero pads a new section to a dll or exe, you only have to specify a name and
  198. the size. The only problem is that (according to NeuRal_NoiSE in his essay) HIEW
  199. can't assemble a jump to this section, you must use sice to get the opcodes.
  200. There is also a nice program, called "OpGen" by NeuRal_NoiSE himself, who can
  201. calculate the opcodes of every jump: you feed it with the starting and the
  202. ending virtual address and it will give you the opcodes. For jumps within a
  203. section you can use HIEW: enter "jmp xxxxxx" where xxxxxx is the PHYSICAL offset
  204. of the destination, don't use the virtual one here!
  205.  
  206. Let's return to the ReverseMe. We need to allocate memory for a buffer to hold
  207. the filename and  later for the whole file. If you look at the import-table of
  208. the exe you will find 2 functions for this task:
  209.  
  210. "VirtualAlloc" reserves or commits a region of pages in the virtual address
  211. space of the calling process. Only whole 64k pages are allocated, so if you need
  212. 10 bytes you will actually get 64k. Our edit-control is (according to the
  213. helpfile) limited to 0xFFFF bytes (64k-1), but this is NOT true, the limit is
  214. smaller. You can use "EM_GETLIMITTEXT" to get the exact value, I used 60000
  215. which seems to be okay. Nevertheless, we will allocate 64k which are first used
  216. to retrieve the filename from the FileDialog and later to read the file into
  217. memory. The exact parameters for "VirtualAlloc" are:
  218.  
  219. lpAddress:        can be NULL
  220. dwSize:           we allocate 64 kBytes
  221. flAllocationType: we choose MEM_COMMIT (0x1000)
  222. flProtect:        PAGE_READWRITE (0x4) is okay
  223.  
  224. When we don't need the memory anymore, it will be freed with "VirtualFree":
  225.  
  226. lpAddress:        the Address of our memory
  227. dwSize:           must be 0
  228. dwFreeType:       MEM_RELEASE (0x8000)
  229.  
  230. Now we need some space for the OPENFILENAME structure. Again, we use
  231. VirtualAlloc to allocate the necessary memory (sizeof(OPENFILENAME) = 76 bytes)
  232. and later VirtualFree to free it. It's necessary to initialize the structure.
  233. The allocated memory contains only 0s, this saves us some typing:
  234.  
  235. - size of the structure (important)
  236. - parent window (can be NULL, or you use [esp+10] which is the current handle,
  237.   look below for more about it)
  238. - hInstance (only necessary if we use a custom template, can be 0)
  239. - pointer to a filter (maybe later...)
  240. - pointer for custom filter (not important - NULL)
  241. - size of custom filter (not important - NULL)
  242. - index of current filter (not important  - NULL)
  243. - pointer to filename: very important, we will put our pointer here
  244. - size of file-buffer: use 512 bytes (200h), should be enough although we
  245.   have allocated 64k
  246. - FileTitle, size of FileTitle, Initial Dir and Title can all be NULL
  247. - Flags: OFN_FILEMUSTEXIST (0x1000) is nice
  248. - the other members are also unimportant
  249.  
  250. Where do we store the variables? The reference says, that only the registers
  251. EBX, EDI and ESI don't change if you call Win32-Api functions, all others could
  252. be modified. 3 registers are enough for now, but if you need more you should
  253. consider using the stack. We have also another option. The memory of the
  254. OPENFILENAME structure will be used only once, later we can use it to store our
  255. variables in it, e.g. if we save the offset of OPENFILENAME in esi you can use
  256. [esi+xx] to access the memory.
  257.  
  258. Anything more? Yes, we will need the names of the functions which should be
  259. loaded with "GetProcAddress". I will put these zero-terminated strings at offset
  260. 0x3F00, you can also use the data-section for it. Do what we have done with the
  261. text-section: compare the virtual with the physical size, adjust the virtual one
  262. and you are ready to store more data in it. We have enough space, so there is no
  263. need for this.
  264.  
  265. comdlg32.dll      (virtual offset 0x403F00)
  266. kernel32.dll      (0x403F0D)
  267. CloseHandle       (0x403F1A)
  268. CreateFileA       (0x403F26)
  269. GetOpenFileNameA  (0x403F32)
  270. ReadFile          (0x403F43)
  271. user32.dll        (0x403F4C)
  272. GetDlgItem        (0x403F57)
  273. SetWindowTextA    (0x403F62)
  274.  
  275. The code starts at offset 0x3B40. You can use HIEW to enter it, but be carefull
  276. with the calls like "VirtualAlloc". The address for these procedures must be
  277. looked up in the disassembled file. Search for the functions and you will see
  278. its addresses:
  279.  
  280. VirtualAlloc:       0x00404034
  281. VirtualFree:        0x0040408C
  282. LoadLibraryA:       0x00404028
  283. GetProcAddress:     0x0040402C
  284. GetModuleHandleA:   0x00404044
  285.  
  286. Another way to get these addresses is to use "OpGen" once more. Click on "Lookup
  287. Imports for patching" and the program will give you a list of all imported
  288. functions and its addresses. Now you can use them in HIEW like this:
  289.  
  290. Function:           VirtualAlloc
  291. address:            0x404034
  292. enter in HIEW:      call d,[00404034]
  293.  
  294. HIEW will show you (as a comment) that you actually call VirtualAlloc from
  295. Kernel32.dll. Let's have a look at the asm-code:
  296.  
  297. ; Handle IDM_LOAD
  298. : starting at offset 0x3B40
  299. ;
  300. ; allocate memory for filename buffer
  301. push 4                       ; PAGE_READWRITE
  302. push 1000h                   ; MEM_COMMIT
  303. push 10000h                  ; 64k
  304. push 0                       ; let Windows decide
  305. call VirtualAlloc
  306. mov  edi, eax                ; store pointer in edi
  307.  
  308. ; allocate memory for OPENFILENAME
  309. push 4
  310. push 1000h
  311. push 4Ch                     ; 76 bytes
  312. push 0
  313. call VirtualAlloc
  314. mov  esi, eax                ; store pointer in esi
  315.  
  316. ; initialize the important members
  317. mov [esi], 4Ch               ; size of structure
  318. mov eax, [esp+10h]           ; this is the parent HWND
  319. mov [esi+4], eax
  320. mov [esi+1Ch], edi           ; pointer to filename buffer
  321. mov [esi+20h], 200h          ; size of buffer, 200h is enough
  322. mov [esi+34h], 1000h         ; flags: OFN_FILEMUSTEXIST
  323.  
  324. ; load comdlg32.dll
  325. ; I don't free it, this should be done at program exit
  326. push 403F00h                 ; offset "comdlg32.dll"
  327. call LoadLibraryA
  328. mov ebx, eax                 ; store handle in ebx
  329.  
  330. ; get address of GetOpenFileNameA
  331. push 403F32h                 ; offset "GetOpenFileNameA"
  332. push ebx                     ; dll-handle
  333. call GetProcAddress
  334.  
  335. ; call the function, only 1 parameter
  336. push esi                     ; offset OPENFILENAME structure
  337. call eax                     ; GetOpenFileNameA
  338.  
  339. ; has the user choosen a file?
  340. or eax, eax                  ; eax == 0 ?
  341. jz FINISH                    ; yes, jump to end - use 0x3DA0
  342.  
  343. Wouldn't it be nice to see the filename in the titlebar? Let's do it. We will
  344. need the handle for "user32.dll" and the address of "SetWindowTextA" also later,
  345. so we store them once they are retrieved. The OPENFILENAME structure won't be
  346. used anymore, so we use this memory, you must only keep track where you put all
  347. your variables.
  348.  
  349. ; get handle to "user32.dll"
  350. push 403F4Ch                 ; offset "user32.dll"
  351. call GetModuleHandleA
  352. mov  [esi+20], eax           ; store handle for later use
  353.  
  354. ; get address of SetWindowTextA
  355. push 403F62h                 ; offet "SetWindowTextA"
  356. push eax
  357. call GetProcAddress
  358. mov  [esi+24], eax           ; store address for later use
  359.  
  360. ; call function
  361. push edi                     ; should contain the filename
  362. push [esp+14]                ; push HWND
  363. call eax                     ; SetWindowTextA
  364.  
  365. The user has choosen a file and we will now open and load it. I use
  366. "CreateFileA" and "ReadFile", please check the doc for the exact parameters. As
  367. mentioned above, only about 60000 bytes will be loaded, because the edit-control
  368. can't show more, and even if you load this amount you won't be able to edit the
  369. file until you delete some text. You can use "EM_SETLIMITTEXT" to increase the
  370. limit to a max. of FFFFh.
  371.  
  372. ; open the file
  373. ; get library handle for kernel32.dll
  374. push 403F0D                  ; offset "kernel32.dll"
  375. call GetModuleHandleA
  376. mov  ebx, eax                ; store it in ebx
  377.  
  378. ; get address of CreateFileA
  379. push 403F26h                 ; offset "CreateFileA"
  380. push eax
  381. call GetProcAddress
  382.  
  383. ; call CreateFileA
  384. ; check its parameters in the doc
  385. push 0                       ; hTemplateFile
  386. push 8000080h                ; FILE_ATTRIBUT_NORMAL, FILE_FLAG_SEQUENTIAL_SCAN
  387. push 3h                      ; OPEN_EXISTING
  388. push 0                       ; Security Attributes
  389. push 1                       ; FILE_SHARE_READ is allowed
  390. push 80000000h               ; GENERIC_READ
  391. push edi                     ; our file
  392. call eax                     ; CreateFileA
  393.  
  394. cmp eax, -1                  ; INVALID_HANDLE_VALUE (-1) ?
  395. je FINISH                    ; yes, do nothing, jump to end
  396.  
  397. ; store handle in memory of OPENFILENAME
  398. mov [esi], eax
  399.  
  400. ; get address of ReadFile
  401. push 403F43h                 ; offset ReadFile
  402. push ebx                     ; kernel32.dll handle
  403. call GetProcAddress
  404.  
  405. ; set up parameters
  406. push 0                       ; overlapped structure
  407.  
  408. mov ecx, esi                 ; next parameter is a pointer for read bytes
  409. add ecx, 4                   ; I use esi+4 for it
  410. push ecx                  
  411.  
  412. push EA00h                   ; number of bytes to read (ca. 60000)
  413. push edi                     ; offset of buffer to receive data
  414. push [esi]                   ; filehandle
  415. call eax                     ; ReadFile
  416.  
  417. ; close file, we don't need the handle anymore
  418. push 403F1Ah                 ; offset CloseHandle
  419. push ebx                     ; kernel32.dll handle
  420. call GetProcAddress
  421.  
  422. push [esi]                   ; filehandle
  423. call eax                     ; CloseHandle
  424.  
  425. ; now check how many bytes we have read
  426. mov eax, [esi+4]
  427. or eax, eax                  ; test if 0
  428. jz FINISH                    ; do nothing if no bytes read
  429.  
  430. The file is now loaded and we want to display it. It's necessary to know the
  431. windows-handle of the edit-control. Do we know it? Look at the (disassembled)
  432. code for the messagebox "Nope doesn't work yet." The first parameter is HWND
  433. (last one pushed), and we see: it's stored in edi. If you scroll up a little bit
  434. you will find that [esp+10] is the location where the HWND is right now. This is
  435. the handle of the main window though. I have used a spy to get the handle of the
  436. edit-control and it was always HWND+4, but there is a cleaner approach.
  437.  
  438. You can use "GetDlgItem" to retrieve the windows-handle. You need the HWND of
  439. the parent window and the ID of your child-window or dialog-control. The ID of
  440. the edit-control we can find out if we look at the "CreateWindowEx" code once
  441. more (I have explained every parameter in the Scrollbar-section) - it's 1. If we
  442. have the handle we can use "SetWindowTextA" which actually sends a WM_SETTEXT
  443. message to our control.
  444.  
  445. ; get HWND of edit-control via GetDlgItem
  446. push 403F57h                 ; offet "GetDlgItem"
  447. push [esi+20]                ; handle of "user32.dll"
  448. call GetProcAddress
  449.  
  450. push 1                       ; ID of edit control
  451. push [esp+14]                ; parent window is stored in [esp+10]
  452.                              ; but we have already pushed a DWORD, so
  453.                              ; HWND is now in [esp+10+4]
  454. call eax                     ; GetDlgItem
  455.  
  456. mov  ebx, [esi+24]           ; address of "SetWindowTextA"
  457. push edi                     ; address of filebuffer
  458. push eax                     ; HWND of edit-control
  459. call ebx                     ; SetWindowTextA
  460. jmp  FINISH
  461.  
  462. After writing this code I found out that you can also use "SetDlgItemText" to
  463. set the text of the control. This function does exactly the same and is shorter
  464. to code. :) The parameters are almost the same, you need the HWND of the parent
  465. window, the ID of your control and the pointer to the new text. I leave this as
  466. an exercise for you.
  467.  
  468. Now we are ready. Only some cleanup has to be done: free all memory allocated
  469. with VirtualAlloc, pop the registers edi, esi and ebx, and finally return. This
  470. finishing code starts at offset 0x3DA0, so jmp (je, jz) FINISH means that you
  471. must enter "jmp 03DA0" in HIEW. It will generate the right opcode for this jump.
  472.  
  473. FINISH:
  474. ; free memory
  475. push 8000h                   ; MEM_RELEASE
  476. push 0
  477. push esi                     ; OPENFILENAME
  478. call VirtualFree
  479. push 8000h
  480. push 0
  481. push edi                     ; filename buffer
  482. call VirtualFree
  483.  
  484. pop edi
  485. pop esi
  486. pop ebx
  487. ret 10h
  488.  
  489. Puh, that was much code. Does it work? YES!!! Great. I must say that it's much
  490. work to do something like this, you must be very carefull (and concentrated)
  491. while adding the code and the right offsets in HIEW.
  492.  
  493. 4. File saving
  494. ==============
  495.  
  496. Now that we have figured out how to load a file it shouldn't be a problem to
  497. save it. You must (again) allocate memory, initialize the OPENFILENAME
  498. structure, call GetSaveFileNameA, create a file, get the contents of the
  499. edit-control (this time with "GetDlgItemTextA") and save everything with
  500. "WriteFile". Here is the code, starting at offset 0x3C70. Don't forget to set
  501. the entry of the jumptable (0x1270) to 0x403C70! After reading the previous part
  502. you shouldn't have any problems to understand this one as well.
  503.  
  504. ; allocate memory for filename buffer
  505. push 4                       ; PAGE_READWRITE
  506. push 1000h                   ; MEM_COMMIT
  507. push 10000h                  ; 64k
  508. push 0                       ; let Windows decide
  509. call VirtualAlloc
  510. mov  edi, eax                ; store pointer in edi
  511.  
  512. ; allocate memory for OPENFILENAME
  513. push 4
  514. push 1000h
  515. push 4Ch                     ; 76 bytes
  516. push 0
  517. call VirtualAlloc
  518. mov  esi, eax                ; store pointer in esi
  519.  
  520. ; initialize the important members
  521. mov [esi], 4Ch               ; size of structure
  522. mov eax, [esp+10h]           ; this is the parent HWND
  523. mov [esi+4], eax
  524. mov [esi+1Ch], edi           ; pointer to filename buffer
  525. mov [esi+20h], 200h          ; size of buffer, 200h is enough
  526.  
  527. ; load comdlg32.dll
  528. push 403F00h                 ; offset "comdlg32.dll"
  529. call LoadLibraryA
  530. mov ebx, eax                 ; store handle in ebx
  531.  
  532. ; get address of GetSaveFileNameA
  533. push 403F71h                 ; offset "GetSaveFileNameA"
  534. push ebx                     ; dll-handle
  535. call GetProcAddress
  536.  
  537. ; call the function
  538. push esi                     ; offset OPENFILENAME structure
  539. call eax                     ; GetSaveFileNameA
  540.  
  541. ; has the user choosen a file?
  542. or eax, eax                  ; eax == 0 ?
  543. jz FINISH
  544.  
  545. ; get handle to "user32.dll"
  546. push 403F4Ch                 ; offset "user32.dll"
  547. call GetModuleHandleA
  548. mov  ebx, eax                ; store handle in ebx
  549.  
  550. ; get address of SetWindowTextA
  551. push 403F62h                 ; offet "SetWindowTextA"
  552. push eax
  553. call GetProcAddress
  554.  
  555. ; call function
  556. push edi                     ; should contain the filename
  557. push [esi+4]                 ; push HWND
  558. call eax                     ; SetWindowTextA
  559.  
  560. ; get address of GetDlgItemTextA
  561. push 403F82h                 ; offet "GetDlgItemTextA"
  562. push ebx
  563. call GetProcAddress
  564.  
  565. ; call GetDlgItemTextA
  566. ; The text won't be stored in edi because it still contains the filename
  567. ; which I will need later. I use edi+100h, no filename is THAT long and
  568. ; the buffer is still big enough for the max. 60000 bytes.
  569. push FEFFh                   ; max. size of string
  570. mov  ecx, edi
  571. add  ecx, 100h
  572. push ecx                     ; where to store the string
  573. push 1                       ; ID of edit-control
  574. push [esp+1C]                ; windows-handle
  575. call eax
  576.  
  577. or   eax, eax                ; success?
  578. jz   FINISH
  579. mov  [esi+10], eax           ; store number of bytes retrieved
  580.  
  581. ; open the file
  582. ; get library handle for kernel32.dll
  583. push 403F0D                  ; offset "kernel32.dll"
  584. call GetModuleHandleA
  585. mov  ebx, eax                ; store it in ebx
  586.  
  587. ; get address of CreateFileA
  588. push 403F26h                 ; offset "CreateFileA"
  589. push eax
  590. call GetProcAddress
  591.  
  592. ; call CreateFileA
  593. ; check its parameters in the doc
  594. push 0                       ; hTemplateFile
  595. push 8000080h                ; FILE_ATTRIBUT_NORMAL, FILE_FLAG_SEQUENTIAL_SCAN
  596. push 2                       ; CREATE_ALWAYS
  597. push 0                       ; Security Attributes
  598. push 0                       ; no sharing allowed
  599. push 40000000h               ; GENERIC_WRITE
  600. push edi                     ; our file
  601. call eax                     ; CreateFileA
  602.  
  603. cmp eax, -1                  ; INVALID_HANDLE_VALUE ?
  604. je FINISH                    ; do nothing, jump to end
  605.  
  606. ; store handle in memory of OPENFILENAME
  607. mov [esi], eax
  608.  
  609. ; get address of WriteFile
  610. ; I thought this function was already imported. Deadly wrong!
  611. ; My computer crashed several times...
  612. push 403F92h                 ; offset "WriteFile"
  613. push ebx
  614. call GetProcAddress
  615.  
  616. ; call WriteFile
  617. push 0                       ; overlapped structure
  618. mov ecx, esi                 ; pointer to DWORD for written bytes
  619. add ecx, 8                   ; I use [esi+8]
  620. push ecx                     ; push the address
  621. push [esi+10]                ; number of bytes to write
  622. mov ecx, edi                 ; the buffer starts at edi+100h
  623. add ecx, 100h
  624. push ecx                     ; push the buffer
  625. push [esi]                   ; filehandle
  626. call eax                     ; WriteFile
  627.  
  628. ; close file, we don't need the handle anymore
  629. push 403F1Ah                 ; offset CloseHandle
  630. push ebx                     ; kernel32.dll handle
  631. call GetProcAddress
  632.  
  633. push [esi]                   ; filehandle
  634. call eax                     ; CloseHandle
  635.  
  636. jmp FINISH
  637.  
  638. The FINISH stuff is the same, starting at physical offset 0x3DA0. Don't use the
  639. virtual offset in HIEW, it will be calculated at runtime. Virtual offsets are
  640. only needed for strings and for the jumps of the jumptable.
  641.  
  642. 5. Conclusion
  643. =============
  644.  
  645. That's it and I am burnt out. I hope you got the idea HOW to add code to an 
  646. unknown target without having the source. The "ReverseMe" is quite small so you 
  647. have to use GetProcAddress very often. In a normal application MANY functions 
  648. are already imported and ready to use. Read NNs essay how to add new menu-items 
  649. and how to handle these messages.
  650.  
  651. 6. Greetings:
  652. =============
  653.  
  654. Knotty Dread
  655. NeuRaL NoiSE (his essay ROCKS)
  656. douby
  657. s^witz
  658. all DREAD members (you know show you are)
  659.  
  660.  
  661.  
  662. Comments, critics, improvements go to:
  663. andreas.theDragon@gmx.net
  664.  
  665.  
  666. finished: 2000-06-01
  667.  
  668.