any chance you can get this to work on wine ;P?
No Kevin. The IAT table if for functions only. It holds no variables. The VTable can hold variables and functions and the variable can be an object or a pointer to one.
I'll try wine in a sec and see if it works on that.
I am Ggzz..
Hackintosher
Ah, ok. Would you be willing to give a lesson on the basics of IAT and VTables? I tried looking at some of your previous threads, and I see references to them before, however I don't see any in depth explanation of them. Granted I only looked at the first page of posts on the OpenGL thread... None the less, I'm not entirely sure what they are besides some set of information relating to objects and/or functions. Are they [basically] what a pdb is to a typical dll? Or are they far more, granting us the direct access to the functions, as if they were a dll and pdb combined?
My Outdated ScriptsEdgeville Log Cutter | Edgeville AIO Jewelry | AIO Pickpocketer | Urn Activator | Slayer Tower | Slaying KuradalMy Working Scripts: Tutorials:Function Pointers and Why You Should Care! | Forms and Saving Settings | The Magic Behind Programming Tutorial | Recursive Recursion![]()
No I haven't gotten around to recompiling it yet.. Just trying to finish all my school work and stuff.. I'm pretty swamped atm + doing a ton of Objective-C and teaching.. :l
I don't mind writing a tutorial.. I wrote you a short snippet in the last 5 mins + a little more to describe it.. I don't have time atm to format the below into nice bullet and keyword highlighting and stuff so bare with me..
C++ Code:#include <iostream>
#include <windows.h>
class Child
{
public:
virtual void PrintOne() {std::cout<<"PrintOne Called!\n";}
virtual void PrintTwo() {std::cout<<"PrintTwo Called!\n";}
virtual ~Child() {}
};
DWORD* GetVTableAddress(void* pObject)
{
return *reinterpret_cast<DWORD**>(pObject);
}
void HookFunction(DWORD* VTable, void* HookFunc, void* OldFunc, int Index)
{
//Enable writing to the VTable
DWORD OldProtect = 0;
VirtualProtect(&VTable[Index], sizeof(DWORD), PAGE_READWRITE, &OldProtect);
//Save Old Function
*reinterpret_cast<DWORD*>(OldFunc) = VTable[Index];
//Overwrite Address with New Function
VTable[Index] = reinterpret_cast<DWORD>(HookFunc);
//Restore Old Protection
VirtualProtect(VTable, sizeof(DWORD), OldProtect, &OldProtect);
}
void Hooked_PrintOne(void* this_ptr)
{
std::cout<<"Hooked PrintOne Called!\n";
}
void Hooked_PrintTwo(void* this_ptr)
{
std::cout<<"Hooked PrintTwo Called!\n";
}
int main()
{
void (*OldFunc)(void* this_ptr) = NULL; //A function pointer to backup the old class function.
void (*OldFunc2)(void* this_ptr) = NULL; //same thing..
Child* child = new Child();
DWORD* VTable = GetVTableAddress(child);
std::cout<<"Calling child->Print.. (not hooked yet)\n\n";
child->PrintOne();
child->PrintTwo();
HookFunction(VTable, reinterpret_cast<void*>(&Hooked_PrintOne), &OldFunc, 0); //Hook function VTable[0]
HookFunction(VTable, reinterpret_cast<void*>(&Hooked_PrintTwo), &OldFunc2, 1); //Hook function VTable[1]
std::cout<<"----------------------------------------\n\n";
std::cout<<"Calling child->Print.. (hooked)\n\n";
child->PrintOne();
child->PrintTwo();
std::cout<<"----------------------------------------\n\n";
std::cout<<"Calling Original child->Print.. (hooked)\n\n";
OldFunc(NULL);
OldFunc2(NULL);
delete child;
}
In the above, we created a class called Child. Child has two virtual functions. Without the virtual table, child cannot be overriden or inherited from.
Next we created a function to get the VPointer. The VPointer is a pointer to the VTable. The VPointer is always the first 4 bytes of a class unless specified otherwise (in that case it will be the last 4 bytes.. very very rare to see this!).
4 bytes = sizeof(DWORD) or sizeof(std::uint32_t).
After that comes any member functions (functions belonging to the class). These are all 4 bytes in length as well. Our GetVTableAddress function gets the VPointer by first casting the Object/class to a DWORD** pointer. This pointer is then dereferenced to get the VTable (a DWORD* aka array of function addresses).
Next we see the HookFunction. How does it work? Well, lets explain the parameters:
The first parameter it takes is of course the pointer to the VTable which we just got from GetVTableAddress.
Next it wants a pointer to a "hook function".. The custom function we created to override the one inside the class.
After that, it takes a pointer to a function that is the SAME SIGNATURE as the one in the class itself. This pointer will be used to backup the original function so we can either call it or restore it later.
Finally, it takes the index in the VTable of the function we want to hook. Array in C++ start at index 0. Thus it only makes sense that the first function is actually index 0 and the next function is index 1 and so on. Note that they are still 4 bytes apart because we are speaking in terms of DWORDs.
Now for how the HookFunction works. What it does is first it backs up the original protection that the memory has on it. Memory in windows has specific "permissions" or properties that protect it from accidental writing. Because of this, if you try to write to an address not allocated explicitly, you get access violations. However, if you make that memory writable, you may write to it freely without any problems at all.
So any how, we change permissions on the VTable[Index] memory to Read/Write and we store the old protection in our variable. That will be used to restore the original protection when finished (also avoids detectability to an extent).
The next line backs up the Class's function address in OldFunc pointer.
Finally, we overwrite the address in the VTable with the address of our HookFunction. Thus when someone calls the class function, it actually calls our hook function instead.
Lastly, we restore the original protection that the class initially had before we went messing with it.
Ah now comes the Hooked functions..
As we should know by now, classes are just a structure holding a group of functions but what makes a class function different from a regular function?
C++ Code:void Regular_Function(const char* some_string)
{
}
void Class_Function(void* this, const char* some_string)
{
}
void RegularFunc()
{
}
void ClassFunc(void* this)
{
}
The above is the difference between a class function and a regular function. A class function is always passed a pointer to the current instance. That pointer is known as the "this" keyword/pointer in many languages. It is used to access variables of that class's instance.
For this reason, our Hooked functions MUST have the "this" pointer as its first parameter! All other parameters may come after!
The rest is pretty self explanatory..
Advantages? Imagine you have something like d3d9.dll which has 50+ functions.. Do you really want to write a wrapper for all 50 functions even if you are only going to hook one?! (Yes I did that for d3d9.dll.. I know)
The answer is NO. You do NOT typically want to do that. You want to write a VTable Hook function and hook as many functions as you need. Nothing more, nothing less. Less work for you overall and its cleaner and easier to read..
Thus a hook can be a couple lines long.. For example, it can take less than 50 lines of code to hook d3d9's EndScene and get colours.
Disadvantages? Requires a loader whereas a wrapper does not since it emulates the original .dll.
That is about it for VTables.. Not sure if I can really teach you IAT because that requires explaining THUNK's and a whole bunch of disassembling and PE info (Portable Executable knowledge)..
I'll think about writing a proper tutorial later or something.. I really got a lot to do and writing the above killed quite a lot of my free time and its 2:07AM.. I gotta leave for school at 5:30AM (no sleep lmao)
Last edited by Brandon; 02-11-2014 at 07:14 AM.
I am Ggzz..
Hackintosher
Hey Brandon... Not sure if it's your plugin or SPS or what... but when I do the following:
1) Make an SPS map (from DirectX or OGL mode) of an "upstairs" area, which has a lot of black on the MM
2) Load both plugins smartPlugins := ['d3d9.dll','OpenGL32.dll'];
3) Set GLX graphics mode
4) Run sps.GetPlayerPOS repeating forever
It always returns -1, -1 (ie not found).
However if I run those same events with the same map, but have rs in OGL mode, it works perfect.
I don't have that issue with ground level maps though so it makes me think it's something to do with the black.
Again my SPS map works in OGL mode but not in GLX, even if I make the map while in GLX mode (however map made in GLX mode WILL work in OGL mode - so it's probs not different colors).
Any ideas/Did that make sense?
Red & Green Salamander Hunter // Construction // Gilded Altar // Major help w/ Kyles Runespan // VWB Smither // PhoenixFeathers // GemCutter // Bonfire // LRC Miner // Spell Tab Maker // ApeAtollAgility // IvyWC // RoguesCooker // Herblore // AshamanButterfly // AshamanPowerMiner // Fletcher // LividFarm
The chunk might be different size in dx mode? Just a thought.
There used to be something meaningful here.
Red & Green Salamander Hunter // Construction // Gilded Altar // Major help w/ Kyles Runespan // VWB Smither // PhoenixFeathers // GemCutter // Bonfire // LRC Miner // Spell Tab Maker // ApeAtollAgility // IvyWC // RoguesCooker // Herblore // AshamanButterfly // AshamanPowerMiner // Fletcher // LividFarm
I am Ggzz..
Hackintosher
Red & Green Salamander Hunter // Construction // Gilded Altar // Major help w/ Kyles Runespan // VWB Smither // PhoenixFeathers // GemCutter // Bonfire // LRC Miner // Spell Tab Maker // ApeAtollAgility // IvyWC // RoguesCooker // Herblore // AshamanButterfly // AshamanPowerMiner // Fletcher // LividFarm
Many thanks for this! Although, it does bring up other questions: like why did you hook everything in your DirectX wrapper? As for the VTable Wrapper disadvantage, is the only disadvantage in that sense the extra work, or does it add extra processing in the startup that is noticeably significant, or something entirely else?
And please, don't feel any need to stress out or lose sleep over stuff like this... I can be patient, and I'm sure everyone else can be as well, no need to run off 3 hours of sleep instead.
My Outdated ScriptsEdgeville Log Cutter | Edgeville AIO Jewelry | AIO Pickpocketer | Urn Activator | Slayer Tower | Slaying KuradalMy Working Scripts: Tutorials:Function Pointers and Why You Should Care! | Forms and Saving Settings | The Magic Behind Programming Tutorial | Recursive Recursion![]()
The wrapper requires everything to be hooked. Hence the word "wrapper". It must export every function that the original .dll exports. Otherwise there can be segmentation faults or simply easy detection.
The VTable is actually "LESS" work than writing a wrapper. The wrapper has way more code. There isn't any performance difference. The reason for the wrapper is to allow Smart to load it. Otherwise it'd have to be injected or loaded as a different name other than d3d9.dll.
As for Ashaman's bug. Is that really the actual minimap? With that one small brown square in the middle? If the colours are indeed correct, the only thing I can think of would be tolerances on the black area. That might not be completely black (0x00000000)
I am Ggzz..
Hackintosher
Ok so I want to learn how run a script with directx how do I go about using the plugin where do I save it how do i make a script use it?
I was under the impression that DirectX and OpenGL share the same colours. It should work. You just need to go to settings on the client and switch to DirectX. The only way I see this not working is if colours are different or if you have the plugins in the wrong place.
I am Ggzz..
Hackintosher
Ok, so even dumbass, inept Me got this to work, and in my own script nonetheless. It has greatly reduced CPU usage on 2 of my 4 open clients, (all 4 are using it), my question is, why not I can has all 4 reduced?
The bots that are still at 25% usage have a noticeably lower fps than the 2 that are reduced. 12Fps vs. 40Fps via Alt+~ in the RS window. (See screenshot)
I absolutely LOVE the fact that it has even reduced CPU by this much, however I can't figure out why it wouldn't do it on all open clients. I haven't tried raising or lowering the task manager priorities for the processes, but I can't imagine that would be the reason because I've never touched those for SMART.
I would love to get the total CPU usage down to around 40% so I can stop cooking my CPU at 98%. Even with a water cooler I'm still running at 55C constantly. But lets be real, I'll just run more bots until I'm at 98% again, but hey, it was a nice thought.
So, do you guys have any advice for me? Or is this a mystery to all?
11mddlu.jpg
I just did some benchmarks on the simplest d3d9 program:
C++ Code:void D3DX::onUpdate(IDirect3D9* D3D9Ptr, IDirect3DDevice9* D3D9Device)
{
int Width = 0, Height = 0;
HDC DC = nullptr;
RECT rect;
GetClientRect(this->Handle(), &rect);
Buffer.resize((rect.right - rect.left) * (rect.bottom - rect.top) * 4);
D3D9Device->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
D3D9Device->BeginScene();
dxReadPixels(D3D9Device, &Buffer[0], DC, Width, Height, D3DFMT_UNKNOWN);
//Save("C:/Users/Brandon/Desktop/Foo.bmp", &Buffer[0], Width, Height);
D3D9Device->EndScene();
D3D9Device->Present(nullptr, nullptr, nullptr, nullptr);
}
Commenting out dxReadPixels drops CPU usage to 1.7%. Reading pixels from the back-buffer jumps CPU usage to 8-10%.
RS without reading the back-buffer has an average CPU usage of: 9-13% over 1 hour run-time.
RS with the plugin without reading the back-buffer has an average CPU usage of 9-13% over 1 hour run-time.
The above makes sense since the plugin is just a wrapper.
However, when I enable reading, the worst CPU usage I got so far was 15% over a 1 hour span. Sometimes it spiked to 22% for a second or two but dropped back down after. This was for the official RS client in Varrock bank. I'm not sure what made it jump.
All of this was tested in Varrock bank with the official client. I found similar values using SMART.
http://i.imgur.com/r3dbNhv.png
I did not try running multiple clients of any kind as that would have skewed the results. I don't have any ideas why it would go up when running multiple clients but if I had to guess, I'd say it's because each client gets less CPU/GPU time as the amount of clients increase.
I am Ggzz..
Hackintosher
Those are about the same values I get when running a single SMART client as well. I just can't understand why 2 clients would always use >20% and 2 clients would always use <10%. They are running the same script, at the same location. My results are the same today, and I zeroed in on one of the >20% clients and it never dropped below that.
I thought maybe the clients were, as you suggested, spiking to 20% and then settling back to 10%, and the 4 clients we're simply trading spikes to appear like the same 2 were always on top. But after a few minutes of watching, the >20%'s are always that high, and the <10%'s are always that low.
The only thing I can imagine, is the first 2 clients I open run at >10% no matter what. After that, the GPU starts dumping graphical processes to the CPU to make up for the extra load. The next time I launch my clients I'll watch and see exactly in which order they start hogging CPU and report back.
BTW Specs are:
CPU - AMD FX-4100 3.6Ghz
GPU - ATI Radeon HD 4670 1GB
Mobo - Gigabyte GA-970A-D3
RAM - 16GB DDR3
There are currently 1 users browsing this thread. (0 members and 1 guests)