Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[GUIDE] Adding Code to Client or Server via a DLL. (Part 1.)

Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
[Guide] Adding Code to Client or Server via a DLL. (Part 1.)

Guide to Adding Code to Client or Server via a DLL.
(Part 1.)

Contents









 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Introduction
Okay... I've been working away on this in spare time, which has become quite difficult with physical technical issues of late, so it's later than I'd hoped. I am also going to cut it down from what I originally planned, because I think the work involved in getting to the goal I originally hoped is too much in a single tutorial. Therefore, though this tutorial doesn't take you to any really great new feature, please take it as a grounding to implementing some of your own, and be patient for more tutorials which will follow.

Make no mistake, this is a long, wordy guide which cannot be padded with pretty pictures or turned into a Video guide. You will need to read it at your own pace, and follow it carefully. If you are already a conversant programmer, and / or really understand Windows PE file format and the Win32 KE Executive Kernel you can "skim" some bits, but I doubt that many of you do, unless you are an "Old Git" like me. That's not a put-down, it's just not something which gets taught these days the way we had to learn it a couple of decades ago... and for this, you are going to need it.

When we change the client, to add items, levels, ages, mixes etc or to translate the built in text language, we often add a section to the PE file. The most common example is the KPTTrans section found in many clients and servers released here. We add code, and data to that section to avoid overwriting important bit's of the client, and allow us more flexibility in out edits. But what if we want to add features of newer clients later on? Well, we can export the KPTTrans (or any other added) section from our old PE, and import it into a new base, but we have to make all the fix-ups pointing to that section in the correct places in the new executable. The alternative, is to find all the new code and data in the new client and replicate it in our old one in the section we have added to it.

Here's another way of doing things. Instead of adding a section to the main PE, why not link in a separate file at the point the PE is loaded into memory? That is exactly what happens when Windows loads DLLs into an executable.

What's the advantage? Well, for one thing, if you change client you don't have to export the section from your old client and import it into your new client, you just add the DLL import to the header of your new client... all the fix ups which call the new DLL are the same as those to call code and data in your added section. This means you can share a DLL, and some instruction on what people should look for to link it in to their client and you share, with this or other communities, the feature implemented in your DLL without giving away your entire client... implementing it in their client is then up to them.

There are other advantages too. If you implement an optional feature which is quite resource intensive, you can allow your users to select which implementation they use. For example, many servers offer "NoLag" options by disabling all the sound files... you could pass sound functions through a DLL, and load either a "full", "minimal" or "nosound" DLL, and only rename 1 file in your options GUI to implement the change... there are other means of selecting which DLL is used too, but I shall speak more on that later on. That example is simplistic, and could be implemented easier in your options GUI, but you have a greater means of customising here. To expand the idea, the reason sound files cause lag is that they are uncompressed and take a long time to load from disk, especially if the user has a slow drive. (UDMA 133 compared to a solid state SATA II drive makes a BIG difference to this "lag") How about compressing the files? MP3s OGGs? That would be great if you have a slow drive and a fast CPU, but if you have a fast drive and a slow CPU it would be disastrous... now you can let users decide how to optimise the game... or even time their system performance and do the tuning for them in the installer, or launcher.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Getting Started
To begin with, we need to know a little bit about DLLs, what they are, and how they are used by the executive Kernel and the programs which load them. I presume you are familiar with the techniques of adding sections (to some extent) and are used to looking at the game.exe in Olly, or some other debugger. As OllyDbg is most commonly used, I will refer to it's interface, but the same information could be found in most others. If that assumption is true, then you know a lot of this already... what I am adding here is understanding of the knowledge you already have. ;)

So, what is a DLL? Essentially it's a program file which doesn't know how to run. It has exactly the same format as an EXE file, but it has no predefined start point. That doesn't sound very useful does it? Well, it is actually. When you load an EXE file, it has only one entry point exported to the OS, and the kernel adds it to the execution roster starting with the code at that point, and runs it. A DLL will export lots of execution start points, but no default one. The idea is that it contains a library of routines that can be called upon by other programs. The extension DLL stands for Dynamic Load-Linkage library. Every OS has them, in most Unixes they are lib.so files, on DOS .OVLs where the norm, but the idea is that if the underlying target changes, you can change the DLL without re-writing the program which calls it.

So if you load game.exe into your debugger (Olly) and look at the memory map, you will see that there are lots of memory sections defined by files other than game.exe. They are DLLs (for the most part).

When you build an Executable file in a compiler, you may get one executable from many many C files and their respective H(eader) files. These are all linked in together into the one file at compile time. But your program actually consists of far more code than just that which you wrote. What Olly shows in it's memory map is the program, as it will run on your machine. When you run the executable, it is then linked again, at run-time, to a whole host of routines in your system... and the combination of your code and system linked code makes up the entire program, which is listed in Ollys memory map.

You can list the DLLs imported by game.exe in a number of tools. Below is the representation in CFF explorer (above) and PE Explorer (below).
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
I believe I have already removed the HanDes.dll linking, because at no point in the game.exe is any routine or data in HanDes.dll ever used... but the header still requests it's presence. I take this as another sign that the "official" PT developers no longer understand the code they are working on.

Most of these are pretty standard libraries of code, and I hope most of you have some understanding of what functions they contain. In case you don't, I'll give a brief run-down, and ask you to check the MSDN for more details:-

  • DSound.dll = DirectX Sound Library, present for DirectX 3 compatability.
  • KERNEL32.dll = The Win32 Kernel, this means we are working as a Win32 program, and not using the POSIX or OS/2 layers.
  • USER32.dll = game.exe is a UserLand program, these functions access parts of the Kernel in a way that does allows us to use the Kernel without running Kernel level code... which would be an "illegal instruction exception". You won't find it in Kernel mode drivers for Windows, but pretty much everything else needs it.
  • GDI32.dll = GDI (Graphic Display Interface) is the Windows drawing routines. This 32bit incarnation was introduced with Win32s for Windows 3.1 and mimics the functionality of Windows NT 3s 32bit GDI, and only standardised by 95 SP1... it's operation (bugs and features) settles down by Win2K. (or, 98SE mostly, but it hasn't really changed since 2K)
  • ADVAPI32.dll = Standard since Win95, Advanced API features not present in older Windows systems. Stuff like User profiles, Security Policies and Group Policy Objects which where in NT 3, but there was no real standard way of using them accross workstations and servers alike.
  • SHELL32.dll = Very useful for launching programs and dlls from within your program, also contains code to look up version strings and icons and such like. All of the Resource section accessing code is in this as well as handy routines for enumerating directory structures and determining the launch program for a .txt file (for example).
  • ole32.dll = This is the Object Linkage Embedding library which pulls in data from other programs. It's used a lot in databases, but also for Drag and Drop functionality and clipboard access. It provides communications between programs. This is how you can paste an Excel spreadsheet into WordPad, for example.
  • DDRAW.dll = This is DirectX 2D drawing routines, again a standard part of DirectX 3. This is what we focused on upgrading our applications to use when we ported from Windows 3.1 to Win95 / NT4.
  • WINMM.dll = Multimedia library for Windows 3.x compatibility... essentially the other half of SDL.
  • SHLWAPI.dll = Shell Windows API... not entirely sure why we would need it, but there it is.
  • WININET.dll = Internet communication library from Windows 95 up. This is used for looking up Clan information on the web server. Essentially this is for Windows.
  • IMM32.dll = This is how Windows handles different users on one system with different language input preferences.
  • WSOCK32.dll = BSD Socket library from Windows 3.x. Most of PT's internet communication goes via this.
As you can see... there is nothing linked which is newer than Win98... though newer builds of PT use GDI32 functions only found in 2K or XP, and don't work right in NT4 or 95... how well they work on ME (for example) I'm not sure. Contrary to many many posts on RZ, PT is NOT a DirectX 7 game, and does not use either Direct3D or OpenGL at all; ever. Many of the libraries used are actually legacy libraries from Windows 3 era, and better alternatives have been available since Win95, suggesting that when development started, it was either on Windows 3.x (NT 3.x) or using an older compiler which didn't have bindings to those newer libraries.

The marketing hype about it being a full 3D game environment is actually misleading. It is as 3D as DOOM for DOS, [strike]no more and no less[/strike], though it can use Windows 32bit kernel and Display Drivers to achieve more than 320x200x8 display resolutions, and can correctly store "bridges" (or multiple floor heights at a single X,Y co-ordinate) which was a limit of the DOOM engine to reduce map size. This may well be the reason for the rope bridges and arch in GOF... just to prove the point. XD
--- EDIT ---
Re-reading this, there clearly is more hardware use than that, and I'm surely doing a dis-service in the last statement. However, I'm really not sure how the image is "layered" from multiple 3D renderings. Translucent textures overlapping clearly go wrong, and forcing anti-aliasing never works right... which it should if D3D rendered everything in one go... so there is some form of software interpretation and placement in-between the rendering of each frame, but it's not as great as I first thought.
---/EDIT ---

Two major questions arise from examining the list:-

  1. Where is XTrap.dll, the npxxx.dlls etc?
  2. Why does OllyDbg show many more DLLs in the list than those listed there?
The answer to question 1, is that they are late-loaded. Which is to say that the code loads them later during the operation of the program. Most DLLs are usually loaded by the kernel executive when it is asked to run an Exe file, but it is possible for the executable to request additional DLLs be loaded into it's memory space after it has already started running. Examples of this use would be plugins for WinAMP... when WinAMP is compiled into an Exe the developers don't know what plugins the user is going to have, or want to use, so they cannot include them all in the header of the Exe file. PT uses this method to "hide" XTrap, nProtect and GameGuard from the PE header information... but we could use it to give users a choice. For example, Diablo II uses it to select DirectDraw, Direct3D, OpenGL or GLIDE rendering of the game. (To give you another idea of what you could achieve with this method)

The answer to the Second question, is that it is entirely possible for a DLL to be dependent on another DLL, and therefore include that in its' import header. This happens more on my x64 system than other x86 systems, because many libraries are linked into WOW64 to allow for the 32-bit compatibility layer. What libraries are loaded on your system, aside from those on the list, will depend greatly on your version of Windows (or Wine or what-ever) and the exact version, service-pack and other software you have installed which may have upgraded those core libraries, or their dependences.

Gets confusing doesn't it? Not really, we don't need to worry about all those dependencies because the Kernel will sort them out for us, and we have to rely on the DLL writers (probably Microsoft for all of these) to have checked the dependencies of these libraries before shipping them out to us poor users. ;)

Okay... so seeing the DLLs imported tells us some things about the capability of the program, and also it's dependencies. But what if we want to add one? Well, I'm going to proceed with an example, which you can follow to get an idea of the principals involved.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Tools Required
Quick links (for those who CBA to RTFM):-

  • (little or no change between 100 and 101, original link died and I believe I've enabled porc.exe as alternative to gorc.exe in the build script)
  • < Actually CFF Explorer will do
You are going to need some basic tools in order to achieve this goal. If our mission is to add some useful code to the PT game.exe (you can transport this idea to the server, or any other program you like) which we are going to write and build as a DLL, then we actually have several "sub-missions".

  1. Write a routine or two, and build them into a DLL file, not an Exe.
  2. Alter the PE header, to cause the Kernel to load a new DLL with the program.
  3. Modify routines in the original PE to use routines in our DLL instead of (or as-well as) their original function.
For mission 1, we need a build environment capable of compiling a Win32 x86 DLL. That's quite specific, so I have to say that you can't write a Java byte code program, build Python, Ruby or Perl executables or use .Net assemblies. You also cannot build an x64, i64, PowerPC or ARM DLL. Windows supports all of these, but they can only be called by programs written for those processors, and that is the reason why MS are pushing .Net. An x86 program can only call an x86 DLL, a PowerPC program can only call a PowerPC DLL, and an x64 (AMD64 or EMT64) program can only call an x64 DLL... a .Net program can call a .Net DLL, or a DLL which is native for the system on which it is running.
Asside as to what all these things are, in case you come accross them:-
Most of us use x86 or x64 systems. So the other alternatives which are listed, and possible... what are they for? Well, there are Windows versions for Intel i64 Itanium processors which where the only 64-bit intel platform before AMD released it's 64bit CPUs, Intels' EMT64 processors use the more popular 64bit processor standard created by AMD. Windows NT 4 was available for IBM/Motorolla PowerPC G2, G3, G4 and even G5 processors as used on older Macs, and MorphOS, AmigaOne, BeBox etc systems. The PowerPC processor was also used in Microsofts' XBox games systems. ARM processors where originally used in Acorn Archimedes and RISC OS systems, but IBM bought out the ARM division (Acorn RISC Machines) and sold ARM2 and StrongARM processors for portable and embedded devices, which is where Windows PE files for Windows CE and Windows Mobile can build ARM PE Executables.
So it's important that the language you program in creates x86 DLLs ONLY. Popular languages like C# and VB.Net don't do this, but similar languages like C++, Objective C, VB6 (can) and FreeBASIC are all fine, provided you use an x86 Win32 build target. Languages like Java and Python are great, but the effort to make them effective for this job is probably more than it's worth.

For my example, I am going to write in native x86 assembler. The reason is simple, one of the first things you are likely to want to do, is copy chunks of code out of your debugger and into notepad, build it as a DLL linked to the game.exe and then you can re-open it in notepad, edit and rebuild your DLL without worrying about boundaries in the exe. You need never touch the exe again to modify that code. You can manually re-write the routine in C or C++ if you want, but you will probably want to work the DLL as x86 assembler first, what-ever else you may do later on.

I've searched for an Assembler that everyone can use freely, that will do the job well, and work with syntax as we are used to seeing it in Olly as much as possible. This might sound like a trivial thing, but it is actually much harder than it sounds. If you look at the options in Olly, you will see that it can format syntax in several different ways, to "look" more like one assembler or another.

The most common Assembler syntax used in the Win32 environment is that of Microsofts MASM, and that is understandable. Microsoft stopped distributing MASM as an Assembler, and not part of a compiler suite back in the days of DOS, so MASM only produces 16bit DOS programs and OVL libraries. Of course, MASM has been upgraded to 32bit as it's used as part of Visual Studios' tool chain to build modern Win32 and Win64 programs, but you can't get that on it's own, and in newer builds it is used as a library, not an independent program. So we need to look elsewhere.
Asside (for those interested in my considerations):-
is bundled independently of Microsoft, and builds a 32bit Windows environment for working with MASM. It's license is reasonably open in terms of what you can do with it, but it imposes some restrictions on how you can license what you have done with it. You can download it and use it freely without payment... but if you want to build your DLL and release the source with a Creative Commons, GNU or BSD license you will probably find that the MASM32 license says that you can't use MASM32 to build that project... legally. The MASM creator(s) hotly dispute that, and claim that the GNU license is at fault for it's viral nature, and their clause is only to prevent the GNU GPL from taking ownership of Microsofts source code... but it still doesn't seem compatible to most GPL programmers.

The Free Software Foundation produce their own GNU Assembler, GASM... but the syntax of that is very strictly bound to Intels' syntax which is practically unreadable. It's also designed to process output from the GNU compiler suite... so it's not really meant to be read, or easy to use.

Okay... so lets look for some more alternatives. is excellent for creating Win32 Executables, it's built as an integrated IDE with Visual programming in mind... that doesn't lend to building DLLs which probably don't have a "Main Window" and is really not very usable in a non-graphical build environment. There is no way you can make a sensible "make" script and just run that to build all your DLLs. (the High Level Assembler) works from very readable and concise code, but it's syntax is nothing like an Olly dump, exactly because of it's formatting, and concise readability. (Turbo Assembler) is produced by Borland, it's syntax is close to MASM but geared towards 32bit Flat model binaries as used in Windows. It defaults to an IDEAL format and DOS 32bit extender binaries which isn't great but easy to work around. It is abandoned and doesn't support MMX, SSE, SSE2, 3DNow! etc... though clones like do. (the Netwide Assembler) is very competent, free, open source and widely used with a syntax that is quite close to MASMs and Olly listings, but it is more commonly used under Unixes and has some peculiarities under Windows, as well as being slow to build. Getting Windows Includes for it that are well supported was rather trying, and I only came across (the Flat Assembler) recently... though that looks good too.

is what I concluded would do the job best. The one quirk over Olly output is that it processes source files in a single pass, and as such, needs to be informed about forward jumps to a label, because it doesn't know about labels till it see them. Its' MACRO processing is excellent and it supports INVOKEs and so on very well. There is a converter that will process MASM, TASM or NASM style code variances in data types and such. He also produces a linker (GoLink) a Windows Resource Compiler (GoRC) and a Debugger (GoDebug) which round the package off nicely.
To get you going without having to research and find all the appropriate includes and so on, I have made a DLL build environment available for you to download:-


[strike] Direct Link
Indirect
Indirect
Indirect
Indirect
[/strike] Indirect
Size = 2.09MB
MD5 = 56484D8BE8B76C888E8D7017EDC3582A
SHA1 = ECD157990253D0E72F9526B77336233B4F93DA1F[/strike]

It's now on [strike] [strike] so shouldn't break. v101 signatures:-​
Size = 2.09MB
MD5 = 6703C7C5AF2FF88FFC29041FF4EE88CF
SHA1 = CF399DCB2BAB215FCC6A51B0F474F081DA27D6D4

Use or to extract it to a location of your choice. (WinRAR sux :p)

Also go and get, and install , and . To install them, just create a folder in "C:\Program Files" (or where ever %ProgramFiles% points on your machine) if you are using an x86 Windows install, or in "C:\Program Files (x86)" (or where ever %ProgramFiles(x86)% points on your machine) if you are using an x64 Windows install, called GoASM, and extract each Zip file into it. My Build Environment will look for them there. (if this is too difficult for people to understand, I may make an installer.

For mission 2, we will use from the RETeam (Reverse Engineering Team) and specifically SantMat. You should find it near the bottom of the page, but you can also Google as this little gem comes up on most of the Reverse Software Engineering blogs, forums and tools repositories. Theoretically, other tools like could be used, and the results of that are really very good, but it's much harder to explain how to use it.

Finally we need to tackle mission 3... the tools for this are simple. You can, of course use a Hex editor... but that's a pain in the backside. It's much easier to use . Go... GET IT, LEARN IT, USE IT. It rocks. XD

I don't mind if you use OllyDbg 1.10 or the final OllyDbg 2.0 Beta. What is the difference? Olly v2 is way faster, Olly 1.1 has a working "plugin" interface. It's great for cracking tough debug detecting encryption or anti-crack executables, but we don't need it for this.

Oh... yea... you'll also want to have a working private PT server and client installation, but what you choose to use there I leave entirely up to you.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Mission 1a - Creating a DLL for PT
Okay, to link a DLL into a program, we need to know what functions (specifically, addresses) it exports. You can add new functions to export from your DLL at a later date, but you will have to re-link them in to the executable, so it's best if you know what functions you intend to export first.

The location of the routines in the code doesn't matter any more, because those addresses will be linked into the program at the point it is loaded into memory. This makes better use of available memory than adding a section to the Exe, and means that code, and data in your DLL can have correct access privileges which won't upset DEP or anything, and will annoy people trying to perform injection on your code. All of which is a good thing.

For this example, as some of you reading my discussion threads may have gathered, I'm going to replace the Win32 library call GDI32:TextOutA()... that is to say, the ANSI version of the , normally located in GDI32.dll. The reasons I'm being so mean, and picking on this little function are:-

  • It has a very simple API functionality, with clearly defined functional parameters. (It's not a complex Object Oriented COM+ library routine like the DirectX calls)
  • It is called by the program an awful lot. (Too many times during each frame considering the complexity of Anti-Aliased True Type Font rendering in Windows)
  • It is key to translating a client. (all displayed text which is not in bitmaps is produced through this)
  • It is used poorly by many clients. (overlapping text, mismatched joins and backgrounds with don't fit the dimensions of the text they are supposed to back etc.)
  • There are better alternatives which produce clearer and more accurate output. (FreeType, Anti-Grain Geometry, Adobe and Apple font renderers and even several Bitmap Blitting game font routines)
Some of these reasons will be illustrated in this guide, some will be left for you, or until later guides.

Other popular contenders where kernel32:VirtualAlloc(), kernel32:ReadFile(), GDI32:BitBlt() and USER32:FindFirstFileA() and FindNextFileA(), but of course, you don't have to pick Win32 APIs and DLL calls to patch, you can export any function you like. The advantage of using a DLL API call for this tutorial is that I can use a named reference which will show up in your code under that name, where code offsets may well vary, so I'm leaving that for a later tutorial, or your own imaginings... supposing that you don't struggle with this, which I think some of you might well do.

Okay, so we've checked out the Win32 API on MSDN, and we know that the API calls for:-
Code:
BOOL TextOut(
__in  HDC [I]hdc[/I],
__in  int [I]nXStart[/I],
__in  int [I]nYStart[/I],
__in  LPCTSTR [I]lpString[/I],
__in  int [I]cbString[/I]);
Which means all the calls to that API are going to PUSH a count of the characters in the string to render, an output string pointer, a Y and an X start position on the DC (Device Context) on which text will be rendered, and the handle to an existing DC.
Aside (for those who are not familiar Device Contexts)
The Win32 environment needs to unify programs access to devices such as Keyboards, Pointing Devices, Displays, Printers etc. These are known as HIDDs, or Human Interface Device Drivers, and they are accessed via User Land programming APIs. Graphics displays have been through a number of incarnations and tried several architectures over the years, and when Windows and other WIMP (Windows, Icons, Menus and Pointer) systems where coming to the fore, there was a great deal of experimentation.

These days, graphics are usually produced in 24 or 32-bit, with a fixed palette formed, either as RGB or BGR (Red, Green and Blue, or Blue Green and Red) with an optional Alpha byte with a 1:1 pixel aspect ratio. However, 16-bit, 15-bit and 8-bit palletised displays used to be popular in a variety of pixel aspect ratios... and stranger techniques like the semi-popular HAM (Hold, And Modify) displays allowed for up to 24k colours simultaneously and un-palletized at only 8-bits per pixel. But accessing and correctly generating such a compressed "RAW" image was so complex that it was only really useful for static, un-animated images.

Other colour models are also popular on non-dynamic displays, such as printers. So CYMK colour space is the most popular, but YCrCb or YUV spaces are also used, and these are very popular among Video encoding and 3D Texture Maps.

Somehow Windows has to consolidate all these different standards and make sure that programs "just work". It does this via Device Contexts, and DIBs. A DIB is a Device Independent Bitmap, and the process of rendering it to a Device Context is the process of translating that DIB into a format which fits the target device in question.

Handles to Device Contexts (hDCs) should only be accessed via Windows APIs to ensure that the correct translation occurs with any information you pass to that DC... even if that DC is using technology which hasn't been invented at the time you write your program... something that was mostly impossible in the days when DOS was our primary OS for PCs. So make no mistake that these little beauties are both important and really really useful.
If we look at an Olly dump of one of those calls, we will see how these parameters are passed to the API (DLL) via the stack.
Code:
[COLOR=Blue][B]mov[/B][/COLOR] [COLOR=YellowGreen][B]edx[/B][/COLOR],[COLOR=DarkOrange][arg3][/COLOR]
[COLOR=Blue][B]push[/B][/COLOR] [B][COLOR=YellowGreen]eax[/COLOR][/B]                                 [COLOR=Green]; /Count => [Arg5][/COLOR]
[COLOR=Blue][B]mov[/B][/COLOR] [B][COLOR=YellowGreen]eax[/COLOR][/B],[COLOR=DarkOrange][arg2][/COLOR]                          [COLOR=Green] ; |[/COLOR]
[COLOR=Blue][B]push[/B][/COLOR] [B][COLOR=YellowGreen]ecx[/COLOR][/B]                                 [COLOR=Green]; |String => [Arg4][/COLOR]
[COLOR=Blue][B]mov[/B][/COLOR] [B][COLOR=YellowGreen]ecx[/COLOR][/B],[COLOR=DarkOrange][arg1][/COLOR]                           [COLOR=Green]; |[/COLOR]
[COLOR=Blue][B]push[/B][/COLOR] [COLOR=YellowGreen][B]edx[/B][/COLOR]                                 [COLOR=Green]; |Y => [Arg3][/COLOR]
[B][COLOR=Blue]push[/COLOR][/B] [COLOR=YellowGreen][B]eax[/B][/COLOR]                                 [COLOR=Green]; |X => [Arg2][/COLOR]
[B][COLOR=Blue]push[/COLOR][/B] [COLOR=YellowGreen][B]ecx[/B][/COLOR]                                 [COLOR=Green]; |hDC => [Arg1][/COLOR]
[B][COLOR=Blue]call[/COLOR][/B] [COLOR=DarkOrange][<&GDI32.TextOutA>][/COLOR]                 [COLOR=Green]; \GDI32.TextOutA[/COLOR]
You should note that each parameter, as it is shown in the C examples in the MSDN, is passed in the reverse order in Assembler, because it is passed on the stack. A stack is a LIFO (Last In First Out) memory block, so the last thing PUSHed on, is the first thing POPed off. ;) The C ordering is based on the order the parameters are read by the routine, not the order they are passed to it.

Okay, so we know that we are going to create a DLL with one exported function, and we know what the parameters of that function are going to be, so now we can start prototyping our DLL code.

If you've already unpacked my DLL Build Environment you will see that it already contains source code for a Test.dll. This DLL does absolutely nothing, but it's files can be used as a template for starting a new project, and you should really have a look at it, and acquaint your self with the code and the tools used. (read the GoASM, GoLink and GoRC manuals)

To start a new DLL project, copy Test.asm, Test.rc and Res\Test.rc to a new files. For this example, I'm going to call the DLL TextRend.dll, and you'll see that I've left Res\TextRend.rc in there by mistake. XD To link to that, you should open your new TextRend.rc and replace the only line in it '#include "Res/Test.rc"' with '#include "Res/TextRend.rc"'

What are these files? Okay, the .asm is your main source code file, the first .rc file is just a link to the Res\blah.rc file which contains the code to be compiled into your resource section. That enables you to include a version string, and even an icon in your DLL if you wish. The two batch files Build.bat and Make.bat allow you to create the executable DLL files from the source code and view any output from the build process in notepad. Build.bat requires the name of the source files and DLL it's being asked to build, but Make.bat will just pass the names of every source it can find to Build.bat one at a time. So by double clicking Make.bat, any DLL you have the full working source for will be pumped out, and a log of the process pops up in notepad.

You can try that now, the output you should see in notepad will be something like this:-
Code:
>Assembly started at 10:42:06.02 on 04/01/2010 
>10:42:06.03 - Building Test 

GoAsm.Exe Version 0.56.8 - Copyright Jeremy Gordon 2001/9 - JG@JGnet.co.uk
Output file: Test.obj

GoRC.Exe Version 0.90.5 - Copyright Jeremy Gordon 1998/2009 - JG@JGnet.co.uk
Output file: Test.res

GoLink.Exe Version 0.26.14 - Copyright Jeremy Gordon 2002/9 - JG@JGnet.co.uk
Output file: Test.dll
Format: win32 size: 3,072 bytes
>10:42:06.16 - Building TextRend 

GoAsm.Exe Version 0.56.8 - Copyright Jeremy Gordon 2001/9 - JG@JGnet.co.uk
Output file: TextRend.obj

GoRC.Exe Version 0.90.5 - Copyright Jeremy Gordon 1998/2009 - JG@JGnet.co.uk
Output file: TextRend.res

GoLink.Exe Version 0.26.14 - Copyright Jeremy Gordon 2002/9 - JG@JGnet.co.uk
Output file: TextRend.dll
Format: win32 size: 3,072 bytes
If it is, as this log shows no errors, you should now have a Test.dll and a TextRend.dll in your build folder.

If you look at them in CFF Explorer or PE Explorer, you will see that they export two functions. DllEntry(), and TestFunction(). The only difference (since we have just copied the files over and renamed the copies, will be the version information... so if you look at the Version / Details tab of the properties of each, File description is either "Test DLL" or "Modular Priston Tale - Text Rendering Library" and the Copyright is either "©ThisYear MyCompany" or "© 2009 Modular Priston Tale". ^_^ (Modular Priston Tale, or ModPT is the working name for where I'm going with all of this)

Now lets look at the source code in the .asm file. We need to understand that.
Code:
[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                           DLLSkeleton.asm
;-----------------+
; by: Iczelion    |
;--------------------------------------------------------------------------------------
;.386
;.model flat,stdcall
;option casemap:none[/COLOR]

[COLOR=Red]#include[/COLOR] [COLOR=DarkOrchid]"include\windows.h"[/COLOR]
[B][COLOR=RoyalBlue]DATA[/COLOR][/B] [COLOR=Blue]SECTION[/COLOR]

[B][COLOR=RoyalBlue]CODE[/COLOR][/B] [COLOR=Blue]SECTION[/COLOR]
[COLOR=RoyalBlue]START[/COLOR]:
[COLOR=Blue][B]EXPORT[/B][/COLOR] [COLOR=RoyalBlue]DllEntry [B]FRAME[/B] [COLOR=DarkOrange]hInst[/COLOR][/COLOR], [COLOR=DarkOrange]reason[/COLOR], [COLOR=DarkOrange]reserved1[/COLOR]
    [B][COLOR=Blue]mov[/COLOR][/B]  [COLOR=YellowGreen][B]eax[/B][/COLOR],[COLOR=Teal]TRUE[/COLOR]
    [B][COLOR=Blue]ret[/COLOR][/B]
[B][COLOR=RoyalBlue]ENDF[/COLOR][/B]

[COLOR=DarkGreen];---------------------------------------------------------------------------------------------------
;                                                This is a dummy function
; It does nothing. I put it here to show where you can insert  functions into
; a DLL.
;----------------------------------------------------------------------------------------------------[/COLOR]
[COLOR=Blue][B]EXPORT[/B][/COLOR] [COLOR=RoyalBlue]TestFunction[/COLOR]:
    [COLOR=Blue][B]ret[/B][/COLOR]
The original source by Iczelion which is written for MASM32 and can be found . I've adapted it to work with GoASM, which is mostly about working Frames and Exports, and the fact that you don't need any of that nonsense about Flat models and .386 stdcall... all of which is obvious because you are creating a Win32 program... and would be really annoying if you wanted to port your assembler to something other than Win32. In GoASM, those sort of things are more correctly Assembler, and Linker switches, and not included in your source code.

This is just 10 lines of code, and only 3 of them are actually machine code instructions.The rest are directives for the Assembler, and linker.

Let's take the machine code first, since you are probably familiar with that from Olly.
Code:
[COLOR=Blue][B]mov[/B][/COLOR] [B][COLOR=YellowGreen]eax[/COLOR][/B],[COLOR=Teal]TRUE [/COLOR]
[B][COLOR=Blue]ret[/COLOR][/B]
[B][COLOR=Blue]ret[/COLOR][/B]
That's all the code that's going to be output by this test example, and the only thing you won't see in Olly is the TRUE bit. Seeing this code in Olly is a little difficult, but we can disassemble it in CFF explorer. If we do, what we see is:-
Code:
push ebp
mov ebp, esp
[COLOR=Red]mov eax, 0x1[/COLOR]
pop ebp
[COLOR=Red]ret 0xc
ret[/COLOR]
The sections in Red, we wrote specifically, the rest the assembler deduced from our build model and the directions we gave it.

So in practical terms TRUE=0x1. It's a constant included in the file include\windows.h. In binary logic terms, any non-zero value is TRUE. Some values are more TRUE than others however, and most systems consider -1 to be the most TRUE value, since it equates to F in twos-complement hexadecimal... specifically, as many Fs as you have room for in whatever value you are using. So FF in a byte (or char in C) FFFF in a word, FFFFFFFF in a long word etc. That's pretty darn TRUE if you ask me. XD TRUE being 1 is very Windows centric... and that's why that is why it's defined in the include\windows.h file. This file also defines a number of other constants, like WM_KEYDOWN and so on for Windows Messages. So anything you want to do with Windows APIs, is probably going to require you to include that header, or define the constants your self... otherwise you are just going to have to look up the value that they equate to. So that's covered #include"include\windows.h" too.
Aside for those not used to using headers or includes.
Having those standard things defined in a set, standard header makes your source code much more readable, and makes it easier for your to write, and understand your code... you don't have to look up the value of WM_CREATE, WM_PAINT, WM_KEYDOWN etc. VK_NUMPAD0, VK_LSHIFT, VK_ESCAPE etc. or any of the other very very useful defines (or equates, depending on your preferred terminology) which it includes.
We know what a mov instruction and a ret instruction do, so we now understand 4 of those 10 lines. What we don't understand, is where those extra instructions that mess around with the EBP and ESP do, and where they came from, since we didn't write them. Well, they are created by GoASMs' smart stack frames. They only happen in the DllEntry function of our DLL, and they happen because we declared DllEntry with the FRAME keyword.

We can declare a FRAME at any point, but using it for a labelled routine is most useful. So DllEntry FRAME declares a FRAME with the label DllEntry. The comma "," delimited terms which follow it are the parameters passed to the function, and because it's an entry point for a DLL, their content is fixed by the Win32 API. The entry point for a DLL (if one exists) is executed at the point a DLL is loaded, and at the point it is terminated, though it can be called at any other point just like any other exported routine. This means that you could "patch" the executable with this routine... if you wanted to.

A FRAME is closed with ENDF, and to understand what it actually does, you need to know how the system stack works in machine code. Assuming you have a reasonable understanding of that, I can tell you that by using FRAME and ENDF anything you do with the stack within that frame, is local to your routine only and will be discarded at the ENDF... so you don't have to worry about corrupting the stack, forgetting to POP something you PUSHed or remembering to PUSH back something you POPed off.

Let's look at declaring routines then, and we should be able to crack the lot of it. The usual way of CALLing or JuMPing to specific addresses in Assembler, is to declare a "label". You can define labels in Olly, either in code or in data by pressing colon ":" and typing a name. This isn't stored in your executable, but in Ollys' .udd file, and means anything referring to that address is either replaced, prefixed or postfixed with that label in the CPU and Dump windows in Olly, which makes your program easier to read than looking at address numbers and offsets. In an Assembler source file, we really don't want to limit our code to specific addresses, that should be left to the linker to decide.

Absolutely anything you like can be a label, so long as it isn't a reserved word (basically any of the x86 mnemonics, or assembler directives) and the Assembler will know that it's a label because it ends in a colon ":".

GoASM requires only one label called START:. The reason for that, is that every executable needs to have a main entry point... even if it's a DLL. Interestingly, the DllEntry export is optional, and because we are building a DLL and not an executable, the START label won't actually do anything, but it still needs to be there for completeness.

The keyword EXPORT tells the Assembler that it should keep a place holder in its' binary that points to this point, and remember the label it is given, so that the Linker can add the fixed up location to the executable as a named exported function in the exe, or dll.

So now there are only two lines out of ten that we don't understand. CODE SECTION and DATA SECTION. These are also cues for the Linker. We already know that a PE file contains several sections for the program, it's data, import and export tables and the resource section. The resource section cannot be compiled in Assembler, because it is not code, but data... okay, so you could declare a shed load of Defined Bytes and stuff, but it makes more sense to use the Windows standard Resource source code. The Exports are handled by the Linker, given cues in our source as we have already seen, and Imports are also given cues in our source if we need to import functions from other DLLs. So all that's left is our Code and Data sections... and these are defined by these statements.

It's possible to have a Test.inc or Test.h with all the data section and #include that file in Test.asm the way we did with windows.h instead of having them all in one file, but what is the point with such a small file to begin with?

Okay... so now you understand all the code in an empty DLL. Wow, a program that does nothing takes so much learning. XD

Now we need to make that empty DLL usable as a replacement for TextOutA(). But before we start work in earnest, let's clean up the comments which make up the bulk of this source, and then I want to show you a different way of managing the exports. Let's change the source to this:-
Code:
[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                           TextRend.asm
;--------------------------------------------------------------------------------------[/COLOR]
[COLOR=Red]#include[/COLOR] [COLOR=DarkOrchid]"include\windows.h"[/COLOR]

[COLOR=RoyalBlue][B]DATA[/B][/COLOR] [COLOR=Blue]SECTION[/COLOR]
[B][COLOR=Blue]ALIGN[/COLOR][/B] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]RetAddr[/COLOR]        [B][COLOR=Blue]DD[/COLOR][/B]    [COLOR=Teal]0x0[/COLOR]
[COLOR=RoyalBlue]EAXStore[/COLOR]    [B][COLOR=Blue]DD[/COLOR][/B]    [COLOR=Teal]0x0[/COLOR]

[COLOR=RoyalBlue][B]CODE[/B][/COLOR] [COLOR=Blue]SECTION[/COLOR]
[COLOR=Blue][B]ALIGN[/B][/COLOR] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]START[/COLOR]:
[COLOR=RoyalBlue]DllEntryPoint [B]FRAME[/B][/COLOR] [COLOR=DarkOrange]hInst[/COLOR], [COLOR=DarkOrange]reason[/COLOR], [COLOR=DarkOrange]reserved1[/COLOR]
    [B][COLOR=Blue]mov[/COLOR][/B]  [COLOR=YellowGreen][B]eax[/B][/COLOR],[COLOR=Teal]TRUE[/COLOR]
    [COLOR=Blue][B]ret[/B][/COLOR]
[B][COLOR=RoyalBlue]EndF[/COLOR][/B]

[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                                TextRend
; This is the main function patched by this DLL, it captures all text rendered to the
; screen, or any other Device Context via the OS TextOut function.
; This is the only OS Function that PT uses to render text... though there are 3 others
; it, or now you, could use instead. Additionally, you could use this to implement a
; custom text renderer, like FreeType.
;--------------------------------------------------------------------------------------[/COLOR]
[COLOR=Blue][B]ALIGN[/B][/COLOR] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]TextRend[/COLOR]: [COLOR=DarkGreen]; Stricktly speaking FRAME hDC, xStart, yStart, lpString, cbString[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [COLOR=DarkOrange][RetAddr][/COLOR]        [COLOR=DarkGreen]; Most important... we must take the return address from the call off the stack![/COLOR]
    [COLOR=Blue][B]mov[/B][/COLOR] [COLOR=DarkOrange][EAXStore][/COLOR],[COLOR=SeaGreen][B][COLOR=YellowGreen]eax[/COLOR] [/B][/COLOR]   [COLOR=DarkGreen]; Store EAX[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [COLOR=YellowGreen][B]eax[/B][/COLOR]                [COLOR=DarkGreen]; Pull the hDC off the stack[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [COLOR=YellowGreen][B]eax[/B][/COLOR]                [COLOR=DarkGreen]; Pull the X off the stack[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [COLOR=YellowGreen][B]eax[/B][/COLOR]                [COLOR=DarkGreen]; Pull the Y off the stack[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [COLOR=YellowGreen][B]eax[/B][/COLOR]                [COLOR=DarkGreen]; Pull the String pointer off the stack[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [COLOR=YellowGreen][B]eax[/B][/COLOR]                [COLOR=DarkGreen]; Pull the Character Count off the stack[/COLOR]
    [COLOR=Blue][B]mov[/B][/COLOR] [COLOR=YellowGreen][B]eax[/B][/COLOR],[COLOR=DarkOrange][EAXStore][/COLOR]    [COLOR=DarkGreen]; Restore EAX[/COLOR]
    [COLOR=Blue][B]push[/B][/COLOR] [COLOR=DarkOrange][RetAddr][/COLOR]        [COLOR=DarkGreen]; Restore the Return Address[/COLOR]
[COLOR=Blue][B]ret[/B][/COLOR]
So, basically we've got rid of the EXPORT statements, and added some ALIGN statements. An ALIGN 4 tells the linker that the address should be aligned to a 32-bit (4 byte) address, which in x86 machine code is addressed faster than a misaligned call, and in some cases may assemble JuMPs and CALLs to smaller byte code.

The main TextRend() function is now taking all the parameters off the stack, and... throwing them away, basically. We have to remember our return address though, and we also have to remember the former state of the Accumulator (EAX register) since that's where I'm going to pull (or POP) all of those stack values into. At the end of the function I restore both these.

This means I have two DWords defined in my Data Section. The syntax (in GoASM) to declare DWord is DD, A byte is DB, a Word is DW and a Quad DQ. This is different from MASM, but similar to NASM, so you need to bare this in mind.

The reason I've done away with the EXPORT statements is that I want you to try out an alternative method of informing the Linker about the exports. In MASM, if you follow Iczlions tutorials or others around the Web, you will see that you have to create a .def file which declares exports. Although GoASM and GoLink use completely different syntax, that method of working is still possible, provided you don't declare exports in the Assembler, and the define file. So I want you to save that, and create a new text file called TextRend.def and fill it with the following code:-
Code:
/Export DllEntryPoint
/Export TextRend
Now you can run Make.bat again, and see that the produced TextRend.dll is still built just the same as before.

You can examine the Build.bat and Make.bat files at your leisure, but basically, if a .def file is present for your build target, it will pass it on to the linker, and if it isn't, it will pass the parameters assuming that your exports are declared in-line in your .asm file.

You may find that method cleaner, or you may not... but if we start sharing DLL code, as I hope we will, you will need to know that either method works the same, and which you choose is up to you.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Mission 2 - Linking Our DLL into the Game Client
Okay, so now we get to the juicy bit... but also the easiest bit. This is where it's finally worth my while giving you some pretty pictures. :D

So, fire up IIDKing, click off the controls in the order illustrated below:-
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
First selecting your game.exe file, then your TextRend.dll and when you have done that, you can select either just the TextRend() API or both TextRend() and DllEntry(). I don't intend to use DllEntry() for this example, but it may be useful to you for your experiments later on.
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
That done, click off "Add Them!!" at the bottom (point 3 of fig.1) and you should have an executable which is linked to TextRend.dll. \o/

If "the proof is in the pudding" I'm going to get myself a big fat slice of Stake and Kidney pudding, with peas and gravy. Open your executable in CFF Explorer or PE Explorer and check the imports.
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
Make sure your game.exe is in your client folder, and that TextRend.dll is either next to it, or somewhere in the path and make sure the game still runs okay.

I'm sure you won't have any problems. No change yet though right? ^_^

If you want to do it the CFF Explorer way, you'll find it's a little more effort (not much) and the results are a lot nicer. You don't get an extra import section.
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
Open the executable in CFF, click the "Import Adder" down the left hand tree view and then click "Add" right in the top centre.

Pick TextRend.dll from the file browser and the exports from it will show up down the bottom.

Click off each one and "Import by name". We exported by name, and ordinals haven't really been "standard" since Win3.1. If you work by ordinal (the numeric order in which the functions are exported) you have to be very careful each time you build a new update to your DLL that the functions order, or numeracy doesn't change... how you do that depends on your compiler / assembler and even more on your linker.

Anyway... when they are all on the list to be imported, just "Rebuild Import Table" and save the executable.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Mission 3 - Modifying the Game Client to Use Our DLL
With the Juicy bit over and done with, and way too easy thanks to IIDKing, we now get to the fun part of modifying the game code to actually use the code that's now loaded with it in our new DLL.

Load your modified game.exe into Olly and, because we are replacing a named API from an existing DLL, right click and "Search for" -> "All intermodular calls"
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
Sort the resulting list by "Destination" and scroll down to the "T"s until you get to GDI32:TextOutA.
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
Each of those calls needs to be replaced with TextRend:TextRend, so double click the first one, and the CPU window will shift it's code listing down to the line "call [<&GDI32.TextOutA>]"

But how are we going to change that? If you double click the line, it translates to a pure address:-
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
So how do you know what the "Address" of your new DLL routine is? And isn't the point of using DLLs that the actual address they are loaded in memory isn't known until the program loads anyway?

Yes; and yes. However, the program will know the address of the import in the import address table, because that is part of the main executables structure. It is filled out by the KE (the Executive Kernel) as the executable is loaded into memory, alongside it's dependent dynamic load linkage (DLL) libraries. This is why the CALL address is in square brackets. The CALL will actually be made to the address pointed to by the contents of (or stored in) the memory located at 5BA048. So in C terms, you are dereferencing a pointer. In machine code parlance we usually refer to this as indirect addressing.
Aside, about high level and low level terminology.
I hope that most people will understand, regardless of the terminology you use, but you should probably be aware that C / C++ people will think in terms of pointers and dereferencing, and Assembler people think in terms of direct, relative or indirect addressing. In C you can reference, point and dereference anywhere you like, Assembler has some limitations on when you can MOV, JMP or CALL relative (in other words, 8 bytes forward, or backward from where we are now, for example) and when you must MOV, JMP or CALL direct (to a specific address) and when you can MOV, JMP or CALL indirect (to a location stored in memory at another specified address). As a rule of thumb, MOVs are largely allowed to address direct or indirect, but not usually relative, JMPs are usually relative or direct, not indirect and CALLs are usually direct or indirect, not relative. How you go on Shifts (SHL, SHR), INCs, DECs, MODs, DIVs, MULs etc is more hit and miss, but usually they work like a MOV.
This method of addressing APIs in DLLs via address tables is key to how modern Operating Systems provide such powerful and standardised software, by building up large libraries of standard routines that everyone can program against. Understanding how it works will get you a long way to understanding how your computer works, and what is happening when it goes wrong. So let's look at the CALL as it is in more detail.

If you right click it, and "Follow in dump" -> "Memory location" you should see something like this:-
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
So you can see that the address that will actually be called is 75A5F9B4... on my system... today. Because, theoretically that address could change, as my system load changes, my system libraries get upgraded etc. etc. In practice, for any particular system, it changes very little, but I do note that the addresses of DLLs loaded by game.exe in my XP x86 system are quite different to those loaded under WOW64 (x86 compatibility layer for x64 Windows) in my Vista x64 system.

Okay, so next we need to find the Import Address Table entry that points to our new DLL routine TextRend(). So first of all, we should check out the memory map in Olly. (click the pale blue 'M' on the toolbar) at this point you should see that there is a new section added to your game.exe by IIDKing called .import. Well that's promising, but until I used IIDKing I wasn't aware that you could have more than one import table in a PE file.

It's formatted a little different to the .rdata section created by the linker that comes with Visual C++ (where the exe was originally created) but if you open it up (by double clicking it) you can scroll up and down (with the scroll bar) and left and right by pressing Control (CTRL) and the Up and Down arrow (cursor) keys. The pointer to the TextRend() routine will highlight in the Address column when you find it... unless you have set Ollys preferences not to show labels. If it is only showing labels and not addresses, you can tell it to show both, or you can calculate the address as +10h from the line above, or -10h from the line below.
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums

--- Update ---
I didn't realize how powerful it was when I first wrote this guide, but for the most part you can reformat the display in Ollys dump from Hex -> 16 bytes + ASCII, to Integer -> Address, and the display changes to listing each 32 bit address on a separate line with labels next to them. ^_^
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
--- /Update ---

So in my case I need to CALL DWord [440E148], the DWord is required, even though Olly doesn't include it in the Assemble window... I'm not sure why, but if you leave it off, the line fails to assemble and you get a warning message. When you have it right, you know you have it right because Olly updates the CPU listing to say "call [&<TextRend.TextRend>]".

As usual with Olly, you can right click the altered line and "Edit" -> "Copy to executable" but you may want to hold off on saving the executable off to file (perhaps with a different name) until you have updated each of the TextOutA() calls to point to TextRend() instead.

Having done that, make sure your newly Ollied executable is in your client install folder, and your newly built TextRend.dll is copied in there too, and run the game.

You should find that you are now typing blind, and the only text that is displayed anywhere is that which is built in to the graphics files. If you can log in without seeing what you are typing, you may well find that you gain a fair bit of extra frame rate too, since we've significantly reduced the processing that needs to go on to render each frame. ^_^

If you are seeing what I've just described, then you have followed everything right so far. Our DLL is imported, and all the TextOut() calls are going through it to be thrown away with no further processing. You can check this in Olly, by opening the Code section of your TextRend.dll and placing a IBP (Instruction Break Point) on the first line of the TextRend() function. That way you can step through it, and see the instructions doing as I said they would in the comments. ^_^

Next we need to make that function do something useful.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Mission 1b - Creating a Useful DLL for PT
Okay, so we've got the game running our code, but it doesn't do anything now. In fact, it's doing less than it was before.

First of all lets get it doing what it used to, so change the listing in TextRend.asm to this:-
Code:
[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                           TextRend.asm
;--------------------------------------------------------------------------------------[/COLOR]
[COLOR=Red]#include[/COLOR] [COLOR=DarkOrchid]"include\windows.h"[/COLOR]

[B][COLOR=RoyalBlue]DATA[/COLOR][/B] [COLOR=Blue]SECTION[/COLOR]
[COLOR=Blue][B]ALIGN[/B][/COLOR] [COLOR=Teal]4[/COLOR]
[COLOR=DarkOrange]RetAddr[/COLOR]        [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]hDC[/COLOR]         [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]xStart[/COLOR]        [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]yStart[/COLOR]        [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]lpString[/COLOR]    [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]cbString[/COLOR]    [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]

[B][COLOR=RoyalBlue]CODE[/COLOR][/B] [COLOR=Blue]SECTION[/COLOR]
[COLOR=Blue][B]ALIGN[/B][/COLOR] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]START[/COLOR]:
[COLOR=RoyalBlue]DllEntryPoint [B]FRAME[/B][/COLOR] [COLOR=DarkOrange]hInst[/COLOR], [COLOR=DarkOrange]reason[/COLOR], [COLOR=DarkOrange]reserved1[/COLOR]
    [COLOR=Blue][B]mov[/B][/COLOR]  [COLOR=YellowGreen][B]eax[/B][/COLOR],[COLOR=Teal]TRUE[/COLOR]
    [B][COLOR=Blue]ret[/COLOR][/B]
[COLOR=RoyalBlue][B]EndF[/B][/COLOR]

[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                                TextRend
; This is the main function patched by this DLL, it captures all text rendered to the
; screen, or any other Device Context via the OS TextOut function.
; This is the only OS Function that PT uses to render text... though there are 3 others
; it, or now you, could use instead. Additionally, you could use this to implement a
; custom text renderer, like FreeType.
;--------------------------------------------------------------------------------------[/COLOR]
[B][COLOR=RoyalBlue]ALIGN[/COLOR][/B] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]TextRend[/COLOR]: [COLOR=DarkGreen]; Stricktly speaking FRAME hDC, xStart, yStart, lpString, cbString[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]RetAddr[/COLOR]]        [COLOR=DarkGreen]; Most important... we must take the return address from the call off the stack![/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR]    [[COLOR=DarkOrange]hDC[/COLOR]]            [COLOR=DarkGreen]; Get the handle to the DC to draw to[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]xStart[/COLOR]]        [COLOR=DarkGreen]; Get the X Coord[/COLOR]
    [B][COLOR=Blue]pop[/COLOR][/B] [[COLOR=DarkOrange]yStart[/COLOR]]        [COLOR=DarkGreen]; Get the Y Coord[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]lpString[/COLOR]]        [COLOR=DarkGreen]; Get the string pointer[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]cbString[/COLOR]]        [COLOR=DarkGreen]; Get the character count[/COLOR]
    [COLOR=Blue][B]INVOKE[/B][/COLOR]    [COLOR=RoyalBlue]GDI32[/COLOR]:[COLOR=RoyalBlue]TextOutA[/COLOR], \
            [[COLOR=DarkOrange]hDC[/COLOR]], \        [COLOR=DarkGreen]; This Invocation is passing our parameters on to TextOut() as they would[/COLOR]
            [[COLOR=DarkOrange]xStart[/COLOR]], \    [COLOR=DarkGreen]; have been done in the first place.[/COLOR]
            [[COLOR=DarkOrange]yStart[/COLOR]], \
            [[COLOR=DarkOrange]lpString[/COLOR]], \
            [[COLOR=DarkOrange]cbString[/COLOR]]
    [COLOR=Blue][B]push[/B][/COLOR] [[COLOR=DarkOrange]RetAddr[/COLOR]]
[COLOR=Blue][B]ret[/B][/COLOR]
Okay, so you can save that, and re-run Make.bat to get your new DLL. But we've got some new syntax in there, and some of it is distinctly not like an Olly listing, so let me explain that while you prove that your typing (or Copy and Paste) skills are still up to scratch. XD

This time I've defined enough DWords to store all the parameters as well as the return address. I don't move the stacked values into the accumulator (EAX, if you remember) any more, so I don't need to remember what it was before I overwrite it any more.

Then we have an INVOKE instruction with some very strange and complex syntax. It's not on mentioned in so what is it all about?

Time was, I used to have to assemble by hand, looking at the tables of OpCodes and working out what the Hex was for the instructions I wanted to write, then POKE them into memory in the ROM based BASIC interpretor, but these days, not only do we have free access to machine code assemblers, but almost all of them are Macro Assemblers. This means that sequences of commonly used instructions can be turned into a Macro, which is like a subroutine, or a function except it is expanded at the time of Assembly, rather than branched to at the programs run-time.

INVOKE is a widely adopted Macro which you can pretty much guarantee any Assembler will have some in-built understanding of. You can create, define or re-define Macros to your hearts content, but INVOKE typically calls function in a library in the OS you are building for. Two advantages of INVOKEing rather than stacking parameters and CALLing are that you can pass parameters in the C order shown in the Windows API documentation, and not in reverse order as they show in a disassembly like Olly. So there's a legibility advantage there. Also INVOKE macros take care of differences in calling conventions between platforms. So this means you can build for Linux without changing the method of calling libraries and libpng.dll (for example) functions can be called just the same as libpng.so, you just change the build target from Win32 PE to Linux x86 ELF. But probably more important to you (as most of you here are Windoze people) is that the calling convention for x64 versions of Windows are different at assembler level than they are for x86 Windows platforms... you don't have to worry about that if you call via INVOKE. Okay... we can't rebuild PT for x64 until we have everything in game.exe in source form, and WOW64 will take care of those differences for a virtualise x86 program running on Win64 platforms... but it's a future consideration surely?

The GoASM INVOKE syntax is pretty simple, the first parameter is the DLL name, and the function name separated by a colon ":" then a comma "," and every parameter which should go to the function is passed after that, one at a time, with a comma separating each one.

To improve the legibility of my source file, I've broken the INVOKE instructions on to multiple lines using the line-continuation character "\". This means I can comment along side it, and you don't have to scroll left and right to read the whole line. In C the compiler ignores new lines and looks for a semi-colon to end an instruction, and in most BASIC languages that support line-continuation characters, the standard is an "_" so you can think of the "\" as one of those.

Most assemblers would need you to #include a .inc file near the top of your source code which should contain all the details of the functions contained in any DLL (or lib.so or .library or whatever your target OS uses) you intend to INVOKE within your source listing. But GoASM is really really smart, and provided the DLL in question is somewhere in your search path it, will figure out the details of the include from the DLLs export section it's self.

It's actually common that you should include a .h file in C or C++ if you are going to utilise an OS library, so this is a really handy short-cut... but you could also use the headers files (.h) as documentation to the OS APIs, so without them, you are going to have to rely more heavily on the .

Okay, so we've restored the original functionality, and we haven't had to touch the game.exe to do it; but what about getting something useful out?

Right, time to INVOKE some more DLL routines from our own DLL. ^_^ The Windows environment allows you to send Debug information out from your application without having to log it to a file, debugger or profiler... and if you look at the list of imported functions, you can see that the game.exe (most versions I've looked at anyway) do make use of that for checking problems with DirectX. Why those calls are still in the release versions I'm not entirely sure, since most users don't have any way of reading those output messages, so you're not going to get sensible bug reports from them with it. It's proved handy for me to know what the DirectX calls are supposed to be doing though. :)

First, I need to make sure you can read system Debug information. The typical way to use it is to connect a Serial Printer, or Dumb Terminal (or PC running a Terminal Emulator) to the COM1: port on the back of your test PC. But that's a lot of effort for very little. The easier way to use it is to grab a copy of , and that will capture them to a list in a window. \o/

This will be my final code listing for this tutorial, as anything else you can probably figure out with the grounding I've given you now:-
Code:
[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                           TextRend.asm
;--------------------------------------------------------------------------------------[/COLOR]
[COLOR=Red]#include[/COLOR] [COLOR=DarkOrchid]"include\windows.h"[/COLOR]

[B][COLOR=RoyalBlue]DATA[/COLOR][/B] [COLOR=Blue]SECTION[/COLOR]
[COLOR=Blue][B]ALIGN[/B][/COLOR] [COLOR=Teal]4[/COLOR]
[COLOR=DarkOrange]RetAddr[/COLOR]        [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]hDC[/COLOR]         [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]xStart[/COLOR]        [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]yStart[/COLOR]        [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]lpString[/COLOR]    [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]
[COLOR=DarkOrange]cbString[/COLOR]    [COLOR=Blue][B]DD[/B][/COLOR]    [COLOR=Teal]0x0[/COLOR]

[COLOR=DarkOrange]szDebug[/COLOR]        [COLOR=Blue][B]DB[/B][/COLOR]    [COLOR=Red]256[/COLOR]    [COLOR=Blue][B]DUP ?[/B][/COLOR]    [COLOR=DarkGreen];Allow room for 255 characters of Debug text.[/COLOR]

[B][COLOR=RoyalBlue]CODE[/COLOR][/B] [COLOR=Blue]SECTION[/COLOR]
[COLOR=Blue][B]ALIGN[/B][/COLOR] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]START[/COLOR]:
[COLOR=RoyalBlue]DllEntryPoint [B]FRAME[/B][/COLOR] [COLOR=DarkOrange]hInst[/COLOR], [COLOR=DarkOrange]reason[/COLOR], [COLOR=DarkOrange]reserved1[/COLOR]
    [COLOR=Blue][B]mov[/B][/COLOR]  [COLOR=YellowGreen][B]eax[/B][/COLOR],[COLOR=Teal]TRUE[/COLOR]
    [B][COLOR=Blue]ret[/COLOR][/B]
[COLOR=RoyalBlue][B]EndF[/B][/COLOR]

[COLOR=DarkGreen];--------------------------------------------------------------------------------------
;                                TextRend
; This is the main function patched by this DLL, it captures all text rendered to the
; screen, or any other Device Context via the OS TextOut function.
; This is the only OS Function that PT uses to render text... though there are 3 others
; it, or now you, could use instead. Additionally, you could use this to implement a
; custom text renderer, like FreeType.
;--------------------------------------------------------------------------------------[/COLOR]
[B][COLOR=RoyalBlue]ALIGN[/COLOR][/B] [COLOR=Teal]4[/COLOR]
[COLOR=RoyalBlue]TextRend[/COLOR]: [COLOR=DarkGreen]; Stricktly speaking FRAME hDC, xStart, yStart, lpString, cbString[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]RetAddr[/COLOR]]        [COLOR=DarkGreen]; Most important... we must take the return address from the call off the stack![/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR]    [[COLOR=DarkOrange]hDC[/COLOR]]            [COLOR=DarkGreen]; Get the handle to the DC to draw to[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]xStart[/COLOR]]        [COLOR=DarkGreen]; Get the X Coord[/COLOR]
    [B][COLOR=Blue]pop[/COLOR][/B] [[COLOR=DarkOrange]yStart[/COLOR]]        [COLOR=DarkGreen]; Get the Y Coord[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]lpString[/COLOR]]        [COLOR=DarkGreen]; Get the string pointer[/COLOR]
    [COLOR=Blue][B]pop[/B][/COLOR] [[COLOR=DarkOrange]cbString[/COLOR]]        [COLOR=DarkGreen]; Get the character count[/COLOR]
    [B][COLOR=Blue]INVOKE[/COLOR][/B]    [COLOR=RoyalBlue]USER32[/COLOR]:[COLOR=RoyalBlue]wsprintfA[/COLOR], \    [COLOR=DarkGreen]; Invoking the wsprintfA function to format a string containing our[/COLOR]
            [COLOR=Blue]ADDR[/COLOR] [COLOR=DarkOrange]szDebug[/COLOR], \        [COLOR=DarkGreen]; details to send to OutputDebugString()[/COLOR]
            [COLOR=Blue]ADDR[/COLOR] [COLOR=DarkOrchid]'RVA: %08lX @%d, %d = %s'[/COLOR], \
            [[COLOR=DarkOrange]RetAddr[/COLOR]], \
            [[COLOR=DarkOrange]xStart[/COLOR]], \
            [[COLOR=DarkOrange]yStart[/COLOR]], \
            [[COLOR=DarkOrange]lpString[/COLOR]]
    [B][COLOR=Blue]add[/COLOR][/B] [B][COLOR=YellowGreen]esp[/COLOR][/B],[COLOR=Teal]24[/COLOR]            [COLOR=DarkGreen]; wsprintfA never cleans it's stack. 6 parameters at 4 bytes each, 6 * 4 = 24[/COLOR]
    [COLOR=Blue][B]INVOKE[/B][/COLOR]    [COLOR=RoyalBlue]KERNEL32[/COLOR]:[COLOR=RoyalBlue]OutputDebugStringA[/COLOR], \
            [COLOR=Blue]ADDR[/COLOR] [COLOR=DarkOrange]szDebug[/COLOR] [COLOR=DarkGreen]; And output it.[/COLOR]
    [COLOR=Blue][B]INVOKE[/B][/COLOR]    [COLOR=RoyalBlue]GDI32[/COLOR]:[COLOR=RoyalBlue]TextOutA[/COLOR], \
            [[COLOR=DarkOrange]hDC[/COLOR]], \        [COLOR=DarkGreen]; This Invocation is passing our parameters on to TextOut() as they would[/COLOR]
            [[COLOR=DarkOrange]xStart[/COLOR]], \    [COLOR=DarkGreen]; have been done in the first place.[/COLOR]
            [[COLOR=DarkOrange]yStart[/COLOR]], \
            [[COLOR=DarkOrange]lpString[/COLOR]], \
            [[COLOR=DarkOrange]cbString[/COLOR]]
    [COLOR=Blue][B]push[/B][/COLOR] [[COLOR=DarkOrange]RetAddr[/COLOR]]
[COLOR=Blue][B]ret[/B][/COLOR]
Okay... there are only a couple of new things to say about this, and the rest should be self-evident. Firstly ADDR value is the opposite of [value]. It's a reverse de-reference, so I'm passing the address of the value, not the contents of the value. Secondly you'll notice that I defined 256 bytes and stated that I don't care what their initial value is with the line szDebug DB 256 DUP ?. You'll also want to look up the API references for and .

If you run DebugView, and then start the game client with this new build of the DLL, you can see all the details of every text string that is rendered to the screen. It's calling address, the location on the screen (or strictly speaking the Device Context) at which it is rendered and what the actual text string was.
bobsobol - [GUIDE] Adding Code to Client or Server via a DLL. (Part 1.) - RaGEZONE Forums
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Other Methods and Ideas
I did ask that people here suggest what they may do with DLLs if they knew how to link them in to their game.exe and I got a couple of questions but very little in the way of answers. That suggests to me that people here are lacking in imagination quite frankly. XD

So what we've done could be done a lot easier with an API tracer, but what we could now do is use that information to trace back to all the text display code, then export that to our DLL and fix the font positioning and so on. We could (as I mentioned in the codes comments) use a different font renderer to display the text. Something of higher quality like , or something faster, like a BitBlit of a cached bitmap font.

We could also use this information to cache the rendered text in an overlay DC or DIB so that when the game asks it to render the same line of text a second time, it's already in a bitmap form and can just be blitted back to the main display in one hit, or we could just optimise the text displaying of the main program so that it doesn't ask a line of text to be rendered more than once, and keeps a handle to the rendering for positioning on the display any time it needs it after that.

Now think of the other things you could change using this method. You could replace Hotuk.ini with registry entries, or a proper .ini file. You could replace the texture loading routines with ones that load PNGs, or DDSs. You could replace the Wave sound loading with OGGs or MP3s, you could replace the response to clicking "Exit" from the system menu with another menu, allowing the user to change detail levels, remap keys etc during the game.

If you can change how Hotuk.ini is stored, then you can change how the server reads all of it's configuration files. Wouldn't it be considerably faster if it go all that data from the SQL server? And if all the SQL database access goes through a DLL you have written and have the source code for, how easy is would it then be to re-target it to MySQL, SQLite, Postgre or DBase?

What if your client didn't get clan data from a web address but via a Telnet connection, or an IRC channel on an IRC server, or even via FTP... wouldn't that improve your security? Now imagine what you would have if that information used your own protocol and went via UDP packets? Once you are confident that the information is going through, and being processed by your code, and you have a source file, you can do anything you like with it, and change it at a whim.

Speaking of security considerations... speaking to friends who run PT on the wild wild web, they are concerned that if large sections of sensitive code where moved into DLLs then couldn't hackers just swap out the DLL to do something you don't want them to? The simple answer to that is that as this project stands, yes, they can. So you would have to counter that, and I have some ideas as to how.

Many of you use the CLSafe_Code to ensure that the client connecting to your server is byte-for-byte the same as the one you give to your users, and hasn't been altered in any way... okay, so you can implement a similar checksum algorithm in your game.exe which checks that the code, and data in the DLLs being loaded by it match the ones you give your players. So if someone modifies or swaps out a DLL, they will have to modify the checksum in your game.exe for it to work, and then, of course, the CLSafe_Code won't match, again. So you've gained a lot of flexibility, made your development environment more creative and really haven't lost any security.

What about this idea (which you know I hate) of encrypting your executable so that nobody can read your code. (Nobody who wouldn't understand the code they could see if it weren't encrypted at least. :S ;) ) Well, of course you can encrypt your DLLs too... but additionally, you can export the code and data sections of your build DLL and import them as raw data into your Executable, so that the whole lot is still packaged up as one file for your users, and still have your creative development environment. If you do this instead of adding your code to a section like KPTTrans, your code is actually better secured by the CLSafe_Code... and not to advertise flaws, I'll let you work out why.

If you keep the source of all your DLLs and make notes about where they patch into the main game.exe, and all your modifications are made in DLLs, you are no longer tied to any particular exe, and can switch and upgrade as you choose. You can also take sections of code from other executables and place them in DLL source files, and link those into your executable, replacing the routines in it.

You can reduce the size of your game.exe by moving code out in to DLLs. This doesn't reduce the overall game size, but if you late-load the DLLs you can get the game to load very very fast and show a progress bar as the libraries are loaded into the client.

You can move levels, ages, maps, item lists etc. etc. into DLL source files. Then you can add new ones at will.

If we all share the DLLs and how we patch them into a client, we can build up an open source alternative client. We may end up with no parts of the original client left. :eek:

Okay... so most of you who work on Private Servers that are open to the public want to keep your little trade secrets, but once you have a library which you are confident simply replicates the existing code, you can share it at that point, then we can all work on our own ideas of what it should be replaced with. You can keep your Uber version for your in-house client and still take advantage of ideas from the community. In return, we have had your help isolating a particular sub-system in the client. We can play with your ideas and you haven't had to give away your client, or server or anything else you'd rather not. You can be confident that you have given away no more, and no less than you intended to.

Therefore, I humbly submit that this is and excellent way for us to collaboratively work on improving PT. I hope you agree, and by all means, please, post below any ideas you have, any improvements you think you can make to this process and any concerns you may have with using it.​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Credits
Okay... Lots of people to thank for this. Most of them not RageZoners, but very deserving non-the-less. Let's see if I can remember them all. :)

SantMat for IIDKing without which this Tutorial would be even longer.
Jeremy Gordon (Jorgon) for GoASM and the Go tools, which really are an excellent low-level Win32 or Win64 tool set.
for the 2.0 version of for GoASM which are the main part of my DLL Build Environment.
and of the for helping me solve my build issues.
for his fantastic Win32 Assembler tutorials and examples, and of course, the DLL skeleton mine is based on.
Oleh Yuschuk for OllyDbg.
for DebugView and all the other fantastic utilities from his SysInternals days and his contributions to the Windows Kernel since he joined Microsoft.
DarkKnightH20 for mentioning that you can link in to different parts of a Tutorial if it's broken into multiple posts, which gave me the idea of posting each chapter as a different post. (naughty though it may be)
And finally, MentaL and all the other Admins here at RaGEZONE, for not slapping me with an infraction despite all the rules I broke posting this tutorial. (Please? I hope you can see why it needed them, and I hope you agree that it's worth it.)​
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
I'm sorry to interupt, but why not simply use LoadLibrary?
That's for later on, exactly because (IMHO) it is not so simple. Thanks for the suggestion, but it had been considered, and was passed out as one of the things I decided to trim out of this first part for simplicity.

I mentioned late loading a couple of times, and while LoadLibrary() is great when everything goes well, if there is a problem with a DLL loaded into your program by the KE from the import section, it's the Kernels job to sort that out. If you use LoadLibrary() there's no safety net, it's your responsibility to check everything and handle any problems. :wink:

When people are looking to secure libraries calculating checksums before loading them and so on, or picking DLLs from multiple user options, LoadLibrary() is a winner, but to start with, lets let the Kernel tell us exactly what's wrong while we are developing the basic principals. Yea? :)
 
Newbie Spellweaver
Joined
Sep 15, 2009
Messages
43
Reaction score
27
You have an interesting part where you talk about the way PT draws its frames. Are you suggesting the 3D is faked in PT like Doom? It is possible to move the camera of PT in any direction giving it the feeling of true 3D..

Also, do you have experience with the DDRAW library?
 
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
It's 3D, but it's software 3D. DOOM 3D wasn't exactly "wrong" though it did take a couple of shortcuts. Shortcuts in Pritson Tales software 3D renderer include rendering separate 3D objects and overlaying them on the view. Partial alpha blending done at the wrong times etc. All of which leads to the strange effects you can see when one texture with an alpha layer overlaps another. :s

It also makes no use of Direct3D or OpenGL and therefore no use of your GPU, which is great if you have a crappy GFX card that overheats when you play WoW or EverQuest, but sux for frame rate, CPU load and general gameplay and presentation.

The experience I have of Direct Draw (the DDraw.dll) has usually been bad. But my experience with all things ActiveX (COM, COM+ etc.) has always been bad. The only Object Oriented libraries I've ever really liked using where the Amiga Intuition libraries (Based on BCPL, not C++) and Borlands VCL (Visual Control Library).

I'm afraid I just don't think in Object Oriented terms, and would rather access Direct Draw through a functional wrapper.

I understand Object Orientation, and can use it. But I understand a Tuxedo and can (with some effort) tie my own Bow-tie. I'd still rather wear jeans and a T-Shirt. XD

Like a Tux, Object Oriented code looks good, but to me it just seems like hard work, for me and the computer. Functional programming is easy, comfortable and looks a little scruffy... like jeans and a T.
 
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
Almost i see everyone isn't interest about problem check debug :D...
Errm. I'm confused by the negatives in that statement. Are you saying that people are, or are not interested in checking for a debugger? Or are you saying that there is a problem with using DLLs in this method, related to debuggers?

I'm not sure.:?:

Anyway... yes, you can check for debuggers, and yes, it's hard to debug a DLL on it's own, but... when you have the source, and can debug it when it's loaded in your program, where is the problem really?

I admit the problem of theft when your code is a DLL, but that isn't as likely server side... and there are ways of securing DLLs to your client, and your client to specific DLLs... it just takes some brain work. :wink:
 
Skilled Illusionist
Joined
Jun 16, 2007
Messages
303
Reaction score
22
You can use function:
IsDebuggerPresent

Example:
call IsDebuggerPresent
test eax, eax
jne @DebuggerDetected
...

IsDebugged:


mov eax, fs:[30h]
mov eax, byte [eax+2]
test eax, eax
jne @DebuggerDetected


NtGlobalFlags


mov eax, fs:[30h]
mov eax, [eax+68h]
and eax, 0x70
test eax, eax
jne @DebuggerDetected


more and more.... blah blah
 

Attachments

You must be registered for see attachments list
Last edited:
Custom Title Activated
Loyal Member
Joined
May 26, 2007
Messages
5,545
Reaction score
1,315
@zahara: Oh yes, quite. I understand you now.

The API is too easy to disable before you start debugging IMHO, but there are many ways to detect debugger and many ways to deal with it.

There are even some reasonable ways to deal with basic disassemblers and decompilers, and in my experience they work better for hindering prying eyes than encrypting.

Side note : the extraction of the Build Environnmnent failed with 7-zip 4.65. Had to upgrade to the 9.10 beta.

Thanks for that note Gregoo. I believe I built that one with 2.7 and tested it also with 6.7 and 3.80. WinRAR reads the catalogue of files, but decompression results in an "epic fail". XD WinRAR really is a sucky program.
6.7 is the last "free for all, for ever" version of ALZip IMS, and I bloged elsewhere on how to remove the most annoying banners for their other tools from it. XD​
It is compressed using the newer LZMA2, but they are in final beta for the .xz format, (which should utilize LZMA2 better than 7z and be more portable) and LZMA2 (according to benchmarks) is faster and uses less memory than standard LZMA for the same compression level.

The fact that it is under the Free Software Foundations GNU license means it will always be freely available to all, and a choice of programs will always be available to deal with the archive. Which is one big reason I like to use it.
 
Last edited:
Junior Spellweaver
Joined
Aug 16, 2009
Messages
148
Reaction score
8
Very nice guide, I like how you organized it with a Contents table.

Thanks.
 
Back
Top