home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / +Sandman / cluster1.txt < prev    next >
Text File  |  2000-05-25  |  23KB  |  567 lines

  1. Remote Administrator v1.11 Tutorial by cLUSTER! - 12th December 1999.
  2.  
  3.  
  4. Now this is truly an excellent piece of software, the best of its kind
  5. really, and it also has one of the most interesting protection schemes
  6. I've come across so far.
  7.  
  8. But even though Dmitry Znosko has put a lot of effort into making this
  9. application virtually uncrackable using traditional cracking approaches,
  10. such as serial-fishing and code-patching, us reversers always come up with
  11. new and brilliant ways of approaching our targets and find our ways about
  12. to make it obey our will!
  13.  
  14. Still, this one has actually been on the stand before although none of the
  15. former crackers have succeeded to make a 100% working crack.
  16.  
  17. The first attempt was made by someone in PGC, I don't remember who,
  18. however, he failed miserably. He managed to remove the NAG, and it also
  19. seemed registered, except for not showing any name and also saying 0 licenses.
  20. Now, this we could have lived with, IF he had at least managed to remove the
  21. checksums, which caused radmin to crash every time you added a new host or
  22. tried to connect to a server. Such a crack is not of much use, disabling the
  23. core functionality of the application.
  24.  
  25. The second attempt made by Staier (tutorial can be found on fravia) on how to
  26. reverse this target by dumping the unpacked module and then disassembling it
  27. using IDA might be an interesting way of doing it, but we still don't end up
  28. with a fully registered application, instead it is still unregistered with the
  29. annoying nag showing and without any name/licenses, only the expiration has
  30. been removed. This method of reversing is too time consuming considering what
  31. we can achieve using it and also that it is fairly easy to find the piece of
  32. code that checks the registration using sice. But obviously that wasn't even
  33. what Staier had in mind, instead he concentrated on removing only the expiration
  34. checks, maybe because a deadlisting does not have any string references to where
  35. the regflag for registration is located ;)
  36.  
  37. After numerous hours of analyzing the code and its bitching, I feel confident
  38. to say that I found a truly excellent way of terminating the need for any
  39. registration code or even any patched code.
  40.  
  41. Turn On, Tune In and may this tutorial shed some light upon new ways to follow
  42. in the art of reverse engineering..
  43.  
  44.  
  45. Tools used: SoftIce, Custom Loader, Some Coke and Loads of Psychedelic Trance.
  46.  
  47.  
  48. NOTE: This application uses relative addresses for its unpacked code, so the
  49.       code-snippets addresses below might differ from the ones you will get
  50.       when reversing radmin.
  51.  
  52.  
  53. For starters, lets look at what we have here..  Running radmin for the first
  54. time tells us that it is an "unregistered copy" and that we can unlock it
  55. entering a registration code.
  56.  
  57. Now we feel all confident.. There is a way to make it registered using a
  58. registration code.. This shouldn't be all that hard, should it?
  59.  
  60. So, we click Enter Code and a dialog box shows up, asking us for the
  61. registration code.. Mhm.. No name.. Either this is gonna be quite easy
  62. to fish.. Using hardcoded serial or maybe parts of the reg. code generates
  63. the other parts of it.. Or if we're out of luck it is going to be a real
  64. bitch of a protection using checksums, maybe even system id and who knows
  65. what else...
  66.  
  67. Enough speculating, lets find out.. First we enter our registration code..
  68.  
  69. 1234554321
  70.  
  71. Yeah, that's it.. This is nice combination of chars since it isn't very likely
  72. to be laying around somewhere in memory already.
  73.  
  74. Now lets break into sice and put a breakpoint on hmemcpy.
  75.  
  76. BPX hmemcpy     ;the almighty undocumented feature especially implemented for
  77. us reversers.. coming soon to a winnt/2k machine near you!  ...not!
  78.                  
  79. And then we click OK.
  80.  
  81. It breaks into sice. Yea yea, it always works damnit. We are so friggin' 3li7e!
  82. ;)
  83.  
  84. Since we don't usually enjoy F12'ing our way out of calls, let's just put a BPRW
  85. on the processes name instead.. (use MOD to see names).. 
  86.  
  87. BPRW radmin     ;this causes softice to break when the applications code starts
  88.                  to execute again.
  89.  
  90. Exit sice and let it rip.
  91.  
  92. WTF?.. Back to the application... Now what's this.. As I see it there are two
  93. possible reason why sice didn't break. One is that the application is packed,
  94. this is the most likely one.. Or it might even be crypted (breakpoint
  95. protected).
  96. The other is that there is a second executable running that handles all the
  97. checking that we missed out on.. Less likely since there is just 2 executables
  98. installed and the other executable being the server. (It could not have been a
  99. DLL/VXD, since sice catches all such calls).
  100.  
  101.  
  102. Well, let's do it all over again.. This time using F12 instead of BPRW.
  103.  
  104. Success.. This time we end up at,
  105.  
  106. B46126 MOV EDI, [USER!EndDialog]   (I take for granted that you use exports.)
  107.  
  108. Now this is quite an odd memorylocation.. But still, it is part of Radmins
  109. code.. (check lower right corner in sice)
  110.  
  111. Still, since I did bring up the subject on external DLL/VXD's used by the
  112. application, let's have a look at which ones radmin uses.
  113.  
  114. QUERY radmin
  115.  
  116. Base  AllocBase   AllocProt   Size   State    Protect   Owner
  117. -------------------------------------------------------------
  118. ....  ......      ..          ..     ..       ..     xxxxxxxx
  119.  
  120.  
  121. While browsing through the Query status of radmin we should look at the
  122. Owner (xxxxxxxx) to locate any used DLL/VXD's.
  123.  
  124. Nopes, nothing out of the ordinary.. Except for a whole lot of memory
  125. space allocated for use and the ordinary Windows DLL's.
  126.  
  127. Out of curiosity we'll have a look at radmins bit sections to see if
  128. there is any sections we recognize (of any known packers)..
  129.  
  130. MAP32 radmin
  131.  
  132. Owner    Obj Name   Obj #   Address          Size        Type
  133. -------------------------------------------------------------
  134. RADMIN   .TEXT      0001    0167:01401000    00008D46    CODE   RO
  135. RADMIN   .RDATA     0002    016F:0140A000    00001952    IDATA  RO
  136. RADMIN   .DATA      0003    016F:0140C000    0002c418    IDATA  RW
  137. RADMIN   .RSRC      0004    016F:01439000    00025500    IDATA  RO
  138. RADMIN   .RELOC     0005    016F:0145F000    00000A30    IDATA  RO
  139.  
  140.  
  141. Nah.. These are all common section names from executables..
  142.  
  143. But looking at the section addresses tells us where radmins code is
  144. mainly located (the packed code that is), and our current EIP being
  145. B46126 confirms that we are indeed tracing a piece of unpacked code.
  146.  
  147. But what do we care?  We are gonna get ourselves a working reg. code.
  148. and if we ever need to investigate what packer has been used, if any
  149. known, we'd just use any of the existing exe analyzers. I'd recommend
  150. File Analyzer since it has proven to detect most common packers and
  151. also gets updated often. Radmin has it's very own packer though, so
  152. none of the existing exe analyzer will detect any packer being used
  153. with the executable.
  154.  
  155. Anyways, let's get with the program.. standard routine here.. we'll just
  156. put a breakpoint-on-range on our reg.code string in memory and let radmin
  157. run and we will probably end up in some comparison routine and we're all
  158. set.. or maybe not.. Off we go..   (NOTE: BPR is not available in WinNT)
  159.  
  160. First of all we need to find out where our reg. code string is located in
  161. memory.. Tracing a couple of lines and we'll end up at ...
  162.  
  163. B46135 MOV EDX, [ESP+C]
  164.  
  165. Do a D EDX to see memory contents.. ahh.. nice, there is our reg. code..
  166.  
  167. (Using sice's S cmd is also very useful to locate strings in memory.)
  168.  
  169. We'll do a BPR EDX EDX+A R to make sice break when radmin reads from our
  170. reg.code string.
  171.  
  172. We exit sice and wait.. Several microseconds later, and we're back in action.
  173.  
  174. This time at...
  175.  
  176. B44618 MOV AL,[EBX]       ;moves 31 to AL  (31=1 from our string 1234554321)
  177. ...... XOR ESI,ESI
  178. ...... PUSH EDI
  179. ...... MOV EBP,EDX
  180. ...... TEST AL,AL         ;checks if there is anything in AL
  181. ...... JZ B446FC          ;if not, that is if we didn't enter any code, it
  182. jumps.
  183. ...... MOV CL, [EBX+1]    ;moves 32 to CL  (next char in our string)
  184. ...... TEST CL,CL         ;checks if there is anything in CL
  185. ...... JZ B446FC          ;if not, this is not a valid code, and it jumps.
  186.  
  187. B44634 CALL B8A14A
  188.  
  189. At this call we need to pay some attention..
  190.  
  191. When tracing into this call, some 280 kb higher in memory, we see yet another
  192. call to a even higher address (4.5 mb higher).
  193.  
  194. B8A14A PUSH 0000001E
  195. ...... CALL FE0540
  196.  
  197.  
  198. Radmin being 390 kb's in its original packed size, then the former piece of code
  199. (b44xxx->b8axxx) makes sense when it comes to size in memory.. But, some 4.5 mbs
  200. further up in memory doesn't. Seems as if radmin has been unpacking itself to
  201. several locations in memory.. But let's not bother with this right now though..
  202. On with the show...
  203.  
  204. Let's trace into the call..
  205.  
  206. FE0540 PUSH AD         (pushes all registers to the stack)
  207.  
  208. <start of code>
  209. ..
  210. ..
  211. FE0571 XOR EAX, [EBX*4+008BD934]  ; checksums the code
  212. ..
  213. ..
  214. loop back to <start> of code until done with range of addresses.
  215. ..
  216. FE059D ADD EAX, D91A65C5  ; adds a static value to the checksum'd EAX value.
  217. ...... MOV EBX, [ESP+20]  ; moves out an address to EBX
  218. ...... SUB EBX, EAX       ; subs the address with what is left in EAX
  219. ...... MOV [ESP+24], EBX  ; moves the results of the sub to the stack.
  220. ...... POPAD              ; pops back all registers
  221. ...... RET                ; exits
  222.  
  223.  
  224. Now what happens in the above code is that it points to an address of
  225. radmins unpacked code and then loops, inc's address and does a checksum
  226. on the code in each loop until it has completed the loop entirely..
  227.  
  228. Then it uses the checksum'd value, which if correct, will results in
  229. the coming address to be executed when it has exited this call and the
  230. previous one.
  231.  
  232. So, if we were to successfully unpack this piece of code (or just use an
  233. inmemory patcher) and patched some of its code, radmin would crash since
  234. the address it'd execute after the checksum routine would be way out
  235. of radmins code.
  236.  
  237. Now I got you thinking.. "This guy sucks.. Nimas problemas.. I'll
  238. just go ahead and patch these checksums.. Been there done that!.."
  239.  
  240. Not this time, this is a no can do situation. Since what we will see in the
  241. coming CALL's we trace is that every piece of checksum code is unique.. 
  242. It never uses the same static value once and that means we would have to
  243. patch each and every one in their very own way.. Sure this is theoretically
  244. possible.. But it'd be plain stupid!
  245.  
  246. Hold it.. Stop right there.. Now I got you thinking again..
  247. "Fuck, this guy is seriously retarded.. It's easy.. Why patch the
  248. checksum routine that contains the static value that is fucking us up?
  249. I'll just go ahead and find out what address it calls once passing
  250. the checksum, and then patch the call that jumps to checksummin'
  251. code and make it call the correct piece of code directly..
  252. This is no match for me..".
  253.  
  254. Bam Bam!.. General Protection Fault.. Since what we will also realize is that
  255. EVERY piece of god damn code in this friggin' application gets checksummored.
  256. That is, if you were to patch a single line of code, it'd trigger the checksum
  257. that checks this particular range of addresses, and removing this checksum
  258. as well would just trigger the next one.. and so on..
  259.  
  260. In other words, this application is a bitch to patch.. So we better hope there
  261. is a good way of fishing/generating a valid reg. code.
  262.  
  263. Back to where we were tracing, that is, after the checksum code.
  264.  
  265. Code snippet of previous traced code -> current EIP ...
  266.  
  267. B44618 MOV AL,[EBX]       ;moves 31 to AL  (31=1 from our string 1234554321)
  268. ...... XOR ESI,ESI
  269. ...... PUSH EDI
  270. ...... MOV EBP,EDX
  271. ...... TEST AL,AL         ;checks if there is anything in AL
  272. ...... JZ B446FC          ;if not, that is if we didn't enter any code, it
  273. jumps.
  274. ...... MOV CL, [EBX+1]    ;moves 32 to CL  (next char in our string)
  275. ...... TEST CL,CL         ;checks if there is anything in CL
  276. ...... JZ B446FC          ;if not, this is not a valid code, and it jumps.
  277.  
  278. B44634 CALL B8A14A
  279.  
  280.  
  281. B8A14A PUSH 0000001E
  282. ...... CALL FE0540
  283. ...... RET                <<<<<<<<<<<<<<<<<<   WE ARE HERE !!
  284.  
  285.  
  286. After this ret, we will end up at the address the checksum ended up
  287. with.
  288.  
  289. B441F0 MOVSX EAX, CL        ;CL=32
  290. B441F3 ADD EAX, -2B         ;32 + -2B = 7
  291. B441F6 CMP EAX, 4F          ;why this? well, 4F+2B = 7A ("z").
  292. B441F9 JA B44380            ;not valid char, jumps.
  293. B441FF JMP [EAX*4+00B44384] ;7*4+B44384 = [B443A0] = 0C 42 B4 -> B4 42 0C
  294.  
  295. B4420C MOV EAX, 00000002
  296. B44214 RET
  297.  
  298. what the above code does is that it takes the second char in our string,
  299. contained in CL from former code, which is 32h = "2", and when the relative
  300. jump is made, the same decimal value is moved into EAX but now in hex form.
  301.  
  302. So, 31 -> 01 , 32 -> 02 ... etc..
  303.  
  304.  
  305. After this ret we're back at main stream again.. Where we were before the
  306. checksum call, at
  307.  
  308. B44639
  309.  
  310. from which it continues to checksum the entered reg. code, looping in a
  311. huge piece of code until the entire reg. code string is done, ending up at
  312.  
  313. B44701
  314.  
  315.  
  316. At this point it is time to ask ourselves what our approach to the situation
  317. is going to be.. Are we going to spend hours and hours analyzing the code
  318. that generates the checksum as well as the coming parts that will compare the
  319. checksum'd result with checksums and checksum and checksums.... get real!
  320. For fucks sake all we want to do is to beat this protection in ANY way and
  321. make this application fully registered as well as functional.. Why put hours
  322. or maybe days of hard work to eventually succeed in making a keygen for this
  323. application. So far this applications protection has been pretty impressive,
  324. so we can take for granted that reversing the protection scheme into being
  325. able to generate our own valid reg. code(s) would be on the edge to insanity.
  326.  
  327. Nah, from here on we will try to locate where radmin compares our faulty
  328. generated checksum-code with whatever and see if we can fool it some way..
  329.  
  330. I know, I know.. Patching the code won't be easy, but that is a problem
  331. we will have to deal with later..
  332.  
  333. Back to reversing..
  334.  
  335.  
  336. After B44701 where it makes a RET it steps back in the code flow to
  337.  
  338. B4614A MOV EAX, [ESP+8]         ; [ESP+8] = 81     (part of checksumming)
  339. B4614E TEST EAX,EAX             ; checks if the reg. code checksumming function
  340.                                   successfully executed.
  341. B46150 JNZ B46157               ; if so, jump
  342.  
  343. B46157 MOV EDX, [ESP+8]         ; [ESP+8] = 81     (part of checksumming)
  344. B4615B LEA ECX, [ESP+000003F4]  ; [ESP+000003F4] = Our regcode, in its
  345.                                                    checksum'd format.
  346. B46162 SHR EDX, 3               ; 81 -> 10   this is the length of our reg. code
  347.                                              in checksum'd format.
  348. B46165 CALL B8A2C0              ; This call creates a registry key
  349.                                   \SOFTWARE\RAdmin\v1.01\ViewType\Data
  350.                                   containing the checksum'd reg. code.
  351. B4616A CALL B8A2CB              ; Gets the registry key reg. code.
  352. ..
  353. ..
  354. B46177 CALL [USER32!SETDLGITEMTEXTA] 
  355. B4617D PUSH 00
  356. B4617F PUSH ESI
  357. B46180 CALL EDI    ; Calls [USER32!ENDDIALOG]
  358.  
  359.  
  360. Until the location above where it calls SetDlgItemTextA, still no
  361. comparison with the checksum'd reg. code had taken place, and after
  362. this call it was all over. The call to EndDialog ended it all.
  363.  
  364. I was a bit confused here but after some more investigation I found out that
  365. the call to the final checking was made within the SetDlgItemTextA call itself.
  366.  
  367. Let's do the following to get to the code that gets called from inside the api..
  368.  
  369. S 0 l c0000000 "02345665432"     (take note, the first char is now an "0")
  370.  
  371. We'll find several memory locations with this string in it.
  372.  
  373. On two of these locations the string will look like this:
  374.  
  375. 023455432100MyFt-L0j9--2
  376.  
  377. Here we put BPR's on those two addresses and then let radmin run again.
  378.  
  379. We will now end up in a loop that generates the checksum'd code.
  380.  
  381. (to those of you that have traced all code until this point, yes it is the same
  382.  code as before that generated the checksum'd reg. code.)
  383.  
  384. Once in this loop we will F12 us out of this call.
  385.  
  386. Now we end up at B44914, from here forward until B44946 the actual comparisons
  387. of the checksum'd code takes place.
  388.  
  389. Now, this is where things starts to get interesting again..
  390.  
  391. Let us have a look at some code snippets...
  392.  
  393. B44946 TEST EAX,EAX           ; Regflag test. Is it a valid checksum'd reg.code?
  394. B44948 JNZ B44A4B             ; If not, jump!
  395. B4494E MOV CL, [ESP+18]       ; Move a byte from [ESP+18] to CL
  396. B44952 MOV AL, 16             ; Move 16 to AL
  397. B44954 CMP CL, AL             ; Compare AL (16) with CL (00)
  398. B44956 JNZ B44A4B             ; If not the same, jump!
  399. B4495C CMP [ESP+19], AL       ; Compare [ESP+19], AL (16)
  400. B44960 JNZ B44A4B             ; If not the same, jump!
  401. B44966 CMP [ESP+1A], AL       ; ....
  402. B4496A JNZ B44A4B             ; ....
  403. B44970 CMP [ESP+1B], AL       ; ....
  404. B44974 JNZ B44A4B             ; ....
  405.  
  406. Let's start with this part of the code..
  407.  
  408. First of all we must pass the regflag test, we'll do a R=0 for the
  409. time being.
  410.  
  411. Next up, it compares the range [ESP+18 - ESP+1B] with 16's.
  412.  
  413. We'll simply E [ESP+18] at B4494E and enter four 16's there.
  414.  
  415.  
  416. Tracing the next few lines leaves us clueless of what it wants,
  417. so let us just exit softice and let radmin run and see what
  418. happens.
  419.  
  420. Fucking great!.. It says Registered.. But, to noone and with 0 licenses..
  421.  
  422. Now this is not as great.. But wtf.. We're on a roll here, let's get
  423. on with the reversing.. We might just get lucky? ;)
  424.  
  425. Let's have a look at what follows...
  426.  
  427. B4497A MOV EAX, [ESP+1E]      ; Moves a word from [ESP+1E] to EAX
  428. B4497E MOV ECX, [ESP+1D]      ; Moves a word from [ESP+1D] to ECX
  429. B44982 MOV EDX, [ESP+1C]      ; Moves a word from [ESP+1C] to EDX
  430. B44986 AND EAX, 000000FF
  431. B4498B SHL EAX, 08
  432. B4498E AND ECX, 000000FF
  433. B44994 AND EDX, 000000FF
  434. B4499A ADD EAX, ECX
  435. B4499C MOV ECX, [ESP+1F]      ; Moves a word from [ESP+1F] to ECX
  436. B449A0 SHL EAX, 08
  437. ..
  438. ..
  439.  
  440. To quickly get a grip on what is happening here we will do some
  441. trial & error.. We edit [ESP+1C - ESP+1F] and put four 11's there.
  442.  
  443. Now exit softice and let radmin run.
  444.  
  445. Ok, now we are kicking some serious asses.. Registered, and with 17 licenses..
  446.  
  447. After a few minutes of playing around with this particular memory location,
  448. putting all kinds of different values there, we have successfully managed
  449. to recreate a working license-string.
  450.  
  451. from [ESP+18 - ESP+1B] we should put 16's, this must be some kind of checksum.
  452.  
  453. from [ESP+1C - ESP+1E] does nothing
  454.  
  455. from [ESP+1F - ESP+20] decides how many licenses there should be (see table
  456. below)
  457.  
  458. from [ESP+21 -> ESP+21+xx UNTIL 00h] string to put after registered to:
  459.  
  460. from [ESP+xx (AFTER 00h) -> ESP+xx) string to put within the parenthesis.
  461.  
  462. Maximum length of the entire string is 3e8h = 1000.
  463.  
  464.  
  465. Licenses table:
  466.  
  467. x x x x
  468. -------
  469. 1         -     16 licenses
  470.   1       -      1 licenses
  471.     1     -   4096 licenses
  472.       1   -    256 licenses
  473. 1 1       -     17 licenses
  474. 2         -     32 licenses
  475. 2   2     -   8224 licenses
  476. F F F F   -  65535 licenses
  477.  
  478.  
  479. So putting this string starting at [ESP+18] would make radmin registered
  480. with maximum amount of licenses:
  481.  
  482. 16 16 16 16 00 00 00 FF FF 43 4C 55 53 54 45 52 00 41 53 53 4B 49 43 4B 45 52
  483.  
  484.  
  485. That's it.. Protection Terminated!..
  486.  
  487. That is if you feel like using sice everytime you want to use radmin..
  488. And we wouldn't want that now would we?
  489.  
  490. What must be done is a sophisticated loader.. A kickass in-memory patcher..
  491.  
  492. And NO, you can NOT use any of the existing ones available on the net, since
  493. they all lack features that makes it possible to patch apps such as this one.
  494.  
  495. I'm sorry to say that even though most of them have been undergoing development
  496. for a long time and they still are very limited.
  497.  
  498. I will now explain how the loader I use to crack radmin with works, but I will
  499. not be giving away any sources with this tutorial.
  500.  
  501. The reason for this is simple, I made this tutorial to show serious reversers
  502. how to approach a target such as radmin, not to ruin the developers of radmin
  503. by sharing all that is needed for people not being able to reverse a target
  504. such as this one themselves.
  505.  
  506. If you are serious about using radmin you SHOULD buy it!.. The developer of
  507. radmin deserves every penny he can get.. He has made an kickass application,
  508. and he isn't asking for much, $25 is well worth spent money if you are
  509. seriously going to use this application.
  510.  
  511.  
  512.  
  513. Loader approach
  514. ---------------
  515. Our goal is to reach to the address of the regflag test and once we've
  516. reached to this point, we need stop radmin from running and move the needed
  517. bytes into memory and then resume the execution of radmins code.
  518.  
  519. To succeed in doing so, we need to implement the following features into our
  520. loader:
  521.  
  522. - We must be able to put breakpoints in code and handle them.
  523. - Read/Write Registers.
  524.  
  525.  
  526. If you manage to make a loader with the above features, you will need to
  527. take the following under consideration to make a fully working loader...
  528.  
  529. - The first breakpoint must be set relative to the start of the first
  530.   unpacked code. Whenever you need to set new breakpoints, and you will
  531.   have to do so since radmins code gets unwrapped progressively, you
  532.   should keep in mind that you must put the breakpoints relative the start
  533.   of the codeblock they belong to, which may be unpacked to different
  534.   addresses each time the program is run...
  535.  
  536.  
  537. Hints: The only static code that jumps to unpacked code is at 1401690.
  538.        From here you should proceed with the next steps.
  539.        
  540.        Use BPR on the unpacked code to find out from where it gets
  541.        unwrapped.
  542.  
  543.        If you by some reason manage to get radmin to expired and want to
  544.        remove the expiration, edit HKLM -> Software and REMOVE the key
  545.        named DATA.
  546.  
  547.        When putting breakpoints at code that is not yet existing in
  548.        memory but is about to be unpacked and executed soon, you can
  549.        not use BPX with the address, you MUST use BPM address X ..
  550.        Also do not forget to use ADDR to change to the right process
  551.        before putting any such breakpoints.
  552.  
  553.  
  554. I hope that this tutorial was of any use.. I've tried to make this tutorial
  555. as detailed as possible, so that not only the very best reversers could get
  556. a grip on what is going on, but also the upcoming masters of the beautiful
  557. art of reverse engineering.
  558.  
  559.  
  560. Last but not least, I pay my deepest respects to MANMACHINE for not only
  561. being a great friend but also for making advanced loaders/patchers and other
  562. useful tools become a reality for me to use. I could never have made this one
  563. without you!
  564.  
  565.  
  566. Radmin Reversed & Tutorialized (c) Dec 1999 - [ cLUSTER! ]
  567. Loader Coding [Src Unrevealed] (c) Dec 1999 - [ mANMACHiNE! ]