Author Topic: Learning DLL's  (Read 4272 times)

Offline alice

  • Administrator
  • Hero Member
  • *****
  • Posts: 553
Learning DLL's
« on: January 21, 2004, 02:26:44 PM »
I want to learn how to reverse engineer OP2 Dlls  Can you help me op2hacker?

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Learning DLL's
« Reply #1 on: January 22, 2004, 05:08:12 PM »
OK. I'll explain how an OP2 DLL works. There are several exported functions in an OP2 mission DLL. (if you don't know what exports, functions, entry points, sections, etc are, go read a C/C++/ASM tutorial.... they'll explain it somewhat. Also, at msdn.microsoft.com search for "PE File Format" and read the MSDN magazine articles "Peering Inside the PE" Part 1 and 2.)

If you have ever looked at the function names using a tool like depends that comes with MSVC++6, you'll see the names of the functions. I'll explain what each one is for:

When I use the word "mission", assume I am referring to any type of scenario (tutorial, colonygame, multi, etc) unless otherwise specified.

First I'll explain the exported variables (these aren't executable code, just entry points to text strings or some other data type)

MapName is the name of the .map file that the mission uses. We have been editing this forever, all current "new maps" just take a mission DLL and edit this string in the .rdata section for the new map file. This can also be referring to

In C++ this would look like:
Code: [Select]
extern "C" char MapName[] = "Filename.map";

LevelDesc is the description that you see in Outpost 2 when you go to play a mission, in the listing. (For example, the LevelDesc of t01.dll reads "Tutorial 1 - Navigating the Map")
This is unimportant to OP2, it is only a description for humans.
In C++ this looks like
Code: [Select]
extern "C" char LevelDesc[] = "Description goes here";

TechtreeName refers to the file within Sheets.vol that contains the particular techtree information, like research etc.
(That's how the tutorials have a limited tech tree, they use a different tech tree file than the full missions)
Currently the only techtrees that can be used (until we reverse engineer the encoding in the text files) are the following:
tutortek.txt - Tutorial limited tech tree
multitek.txt - General purpose techtree, used in multiplayer and colony games
edentek.txt - Eden Campaign tech tree
ply_tek.txt - Plymouth Campaign tech tree
The OP2 demo also has a demo tree, demotek.txt. However this is NOT in the full game (and copying it into the VOL's will not work since it isn't encoded like the full game files are)
In C++ this is:
Code: [Select]
extern "C" char TechtreeName[] = "TECHNAME.TXT";

And now the last variable export, DescBlock. This is what controls what kind of game it is. The DescBlock is different for each type. This is also one of the factors that controls whether it shows in the lists; that's why simply putting a "t", "c", "m" or other letter before a DLL name will not make it show in the list. (But that is still used as well, to determine placement in the lists, along with the DescBlock.)

The DescBlock is a 4 byte (int in C++) that tells OP2 what type of mission.. This could have some work done to decode what each of the bits, etc mean.

Now onto the actual functions that do the work in the mission file.

The single most important export in an OP2 DLL is the InitProc. OP2 calls this when the mission is loaded, and it "starts" the mission. In the InitProc code, the exported functions from OP2 (take a look at outpost2.exe from depends; there are over 300 exported class members etc) are called to do everything from setup of players to creating units and beacons to setting victory/failure conditions and triggers. (I'll explain triggers in greater depth later, little I know about them)

The InitProc returns a BOOL, which in C++ can be either True (1) or False (0). If it returns 1, that means OP2 will execute the mission. If it returns 0, this is a signal to OP2 that an error occurred and OP2 will stop loading the mission (and display an error message, something along the lines of "Could not initialize script file" or something like that). (By the way, OP2 refers the little it does in errors, etc., to DLL's as "Scripts". I don't use that term.. because technically it's not a script... but OP2 does...)

This is one of the major areas of concern for OP2.. We want to figure out what all the functions mean that are called from InitProc.

Now I'll explain triggers before I go into the less significant functions.

All a trigger is a condition that has some sort of action attached to it that will happen if the conditions are true.

In OP2, there are 17 known types of triggers: Attacked, BuildingCount, Count, Damaged, Escape, Evac, Kit, Midas, OnePlayerLeft, Operational, Point, Rect, Research, Resource, Set, Time, and VehicleCount. (No I don't know what each one does or how to set one up, but I know that you can create them in OP2.)
The "action" for OP2 triggers is contained in another exported function called a callback. For those of you not familiar with callbacks, a callback is a function or piece of code that is called/run when it needs to. OP2 calls the callback that is assigned to a trigger when that trigger's condition becomes true, and then that can do certain things (for example, if you get 1000 metals, it creates a building or who knows what)

You can see the names of these callbacks in depends, they are exported along with the other functions.

Victory and failure conditions work on triggers. When a victory/failure condition is created, you assign it a trigger. If that trigger become true (is fired), then that means the victory or failure condition is satisfied, and the game ends at that point if all the victory or failure conditions are satisfied.

In the OP2 DLL's you will see the developers put a function in almost every DLL named NoResponseToTrigger. All it is is a function that takes nothing as a parameter, and returns nothing. It's mainly used when you have a trigger that is also used as the victory/failure condition, and you don't need it to do anything. Also you must assign it a trigger, so you just give it a trigger that is "empty". Usually the NoResponseToTrigger is a Time type.
In C++, NoResponseToTrigger looks like this:
Code: [Select]
void NoResponseToTrigger(void) {
}

Now, onto the less important functions, that are less well known.

AIProc appears to be a function that was going to originally be used in OP2, but it isn't needed because of the trigger system and more advanced AI. So AIProc looks like NoResponseToTrigger - it takes nothing as a parameter, does nothing, and returns nothing. In C++ it looks like this:
Code: [Select]
void AIProc(void) {
}

StatusProc appears to be something that tells OP2 if some error or other bad thing happened. Normally, it returns 0. In C++ it would look like this:
Code: [Select]
BOOL StatusProc(void) {
return FALSE;
}

The last function, GetSaveRegions, is totally unknown. It doesn't exist in all missions, and I'm not sure of what it does (it only has like 4 lines of assembly code), or even what it takes/returns. I have no information on it otherwise.


Well, that's the information I have on DLL's. Happy hacking!

-- op2hacker
« Last Edit: January 22, 2004, 05:28:52 PM by op2hacker »

Offline CK9

  • Administrator
  • Hero Member
  • *****
  • Posts: 6226
    • http://www.outpost2.net/~ck9
Learning DLL's
« Reply #2 on: January 24, 2004, 02:37:37 PM »
sorry to post in here, but I just want to know real quick:

Quote
In OP2, there are 17 known types of triggers: Attacked, BuildingCount, Count, Damaged, Escape, Evac, Kit, Midas, OnePlayerLeft, Operational, Point, Rect, Research, Resource, Set, Time, and VehicleCount.

why don't we experiment with these?  Would it cause problems?
CK9 in outpost
Iamck in runescape (yes, I still play...sometimes...)
srentiln in minecraft (I like legos, and I like computer games...it was only a matter of time...) and youtube...
xdarkinsidex on deviantart

yup, I have too many screen names

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Learning DLL's
« Reply #3 on: January 25, 2004, 02:51:36 PM »
Oops... forgot to open the topic.

We could experiment, just it's harder to add calls to the trigger creation functions in an already existing DLL.

Once we can make our own DLL's experimenting would be easy.

(For you reverse engineerers that want to try this, you can do this:

1) find a suitable spot to add this type of trigger to the DLL... usually inside InitProc.

You could delete code of a useless function like the calls to SetCheats (they don't do anything as far as I know -- Unless OP2 has a loader or something)
Then you could add a jump to an unused part of the file (like at the end of the .text section, there are a lot of nulls: Here's the formula for figuring out jump addresses.

Address = "To" Address - "From" Address - 5

(The hex byte for a Far JMP instruction is E9; remember little endian format (rightmost byte of the dword address first!))

In that section you could then call a trigger creation function and do something with it - then JMP back to right after where you left InitProc. (Otherwise InitProc never returns and you get some error or something)

I haven't tried this but it would work like this.... Still hard to experiment with.
« Last Edit: January 25, 2004, 02:51:46 PM by op2hacker »

Offline alice

  • Administrator
  • Hero Member
  • *****
  • Posts: 553
Learning DLL's
« Reply #4 on: February 08, 2004, 01:31:50 PM »
Ok.  Could you post a template DLL with alot of free space? :)

Also.  Could you explain where the length of the data areas are defined, and how it references them

Thanks.

Offline plymoth45

  • Hero Member
  • *****
  • Posts: 1062
Learning DLL's
« Reply #5 on: February 08, 2004, 03:07:30 PM »
(...)
that is confusing :s

Offline alice

  • Administrator
  • Hero Member
  • *****
  • Posts: 553
Learning DLL's
« Reply #6 on: February 09, 2004, 01:42:01 PM »
Um, we don't have a :S smiley face.... Oh well

I should pin this so we could access it anytime.  :D  

Offline plymoth45

  • Hero Member
  • *****
  • Posts: 1062
Learning DLL's
« Reply #7 on: February 09, 2004, 02:11:15 PM »
tis is time to make a :s smiley

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Learning DLL's
« Reply #8 on: February 09, 2004, 06:54:34 PM »
Quote
Also.  Could you explain where the length of the data areas are defined, and how it references them
What do you mean data areas? like code etc? those would be the sections.

They're defined in the header of the PE file.

There are rules on sections-- you must round up to the next memory page/segment size (4K i think)

that's where the "blank" areas come in in the PE - it's unused page space.

If the section sizes don't align up with the memory page sizes, the file cannot be run.

(That's why you cannot delete or add even a single letter in a PE file -- it throws the alignment off, it's called)

msdn.microsoft.com has info about this stuff, search for "PE Article" and read the parts 1 and 2.

also, in VC++ look at <winnt.h> for struct declares for PE structures.

Offline alice

  • Administrator
  • Hero Member
  • *****
  • Posts: 553
Learning DLL's
« Reply #9 on: February 09, 2004, 07:05:17 PM »
Okay. I can't wait till I can make my own DLLs! :)

Offline Ezekel

  • Sr. Member
  • ****
  • Posts: 307
    • http://ezekel.deviantart.com
Learning DLL's
« Reply #10 on: March 26, 2004, 07:52:14 PM »
obviously you can ^^

as i don't see any new colony maps or campaigns ;)
My mind is quicker then your eyes!

Never fight what you cannot see!!!

----------------------------------------------

The sleeper has awakened... and boy what a hangover!

Offline zanco

  • Full Member
  • ***
  • Posts: 241
Learning DLL's
« Reply #11 on: April 04, 2005, 01:45:04 PM »
I don't want to creat another topic, so I will just post my questions here.
I took a look at the SDK (that you somehow managed to make, thumb-ups), and  I was wondering which functions are beeing exported. I explain myself:
I'm, I guess, an intermediate programmer in C++, so I had to learn all the stuff about dlls on saturday.
So far, I've learned that to export a function from a dll file, you can use:
a) extern "C" __declspec(dllexport) stuff stuff
b ) __declspec(dllexport) stuff stuff
c) extern "C" function prototype, and write the name of function to be exported in a .def file.

However, I looked at the SDK and haven't seen anything like that. May be I haven't studied enough. It would be cool if you told me how you encoded the "exportation"
(?)
.
.
.
is it done with " __cdecl"?


oops, clicked on edit button
« Last Edit: April 04, 2005, 10:23:58 PM by zanco »
if anyone finds and communicate to us that which thus far has eluded our efforts, great will be our gratitude.
          Jakob Bernouilli

"Zanco`, n00b o' The Flares"

Offline BlackBox

  • Administrator
  • Hero Member
  • *****
  • Posts: 3093
Learning DLL's
« Reply #12 on: April 04, 2005, 02:51:32 PM »
We wrote a define:

#define SCRIPT_API extern "C" _declspec(dllexport)

so you can simply put something like: void SCRIPT_API YourTrigger(void);

Offline zanco

  • Full Member
  • ***
  • Posts: 241
Learning DLL's
« Reply #13 on: April 04, 2005, 10:22:08 PM »
okay
if anyone finds and communicate to us that which thus far has eluded our efforts, great will be our gratitude.
          Jakob Bernouilli

"Zanco`, n00b o' The Flares"

Offline Eddy-B

  • Hero Member
  • *****
  • Posts: 1186
    • http://www.eddy-b.com
Learning DLL's
« Reply #14 on: April 05, 2005, 01:48:22 AM »
To add on that: i've added another #define - not that hacker's isn't good, but declaring it this way seemed to make more sense :P
Code: [Select]
#define EXPORT extern "C" __declspec(dllexport)
Good luck on ur quest to understand the DLLs! (thumbsup)  
« Last Edit: April 05, 2005, 01:48:41 AM by Eddy-B »
Rule #1:  Eddy is always right
Rule #2: If you think he's wrong, see rule #1
--------------------

Outpost : Renegades - Eddy-B.com - Electronics Pit[/siz

Offline zanco

  • Full Member
  • ***
  • Posts: 241
Learning DLL's
« Reply #15 on: April 05, 2005, 09:31:07 AM »
nice Eddy!
I read this really good article; if other ppl are interested in learning dll go -->   http://msdn.microsoft.com/archive/default....html/ppc_ll.asp
if anyone finds and communicate to us that which thus far has eluded our efforts, great will be our gratitude.
          Jakob Bernouilli

"Zanco`, n00b o' The Flares"

Offline zigzagjoe

  • Hero Member
  • *****
  • Posts: 626
Learning DLL's
« Reply #16 on: April 28, 2005, 08:40:59 AM »
Hacker: that will work (void SCRIPT_API YourTrigger(void);), but you will get a warning.

You should do it like this: SCRIPT_API void YourTrigger(void);

You don't get any warnings like that