Solved Internal Pattern Scan Returning wrong address

  • CSGO recently moved logic from 'client_panorama.dll' to 'client.dll', you must update all code that uses 'client_panorama.dll' and replace it with 'client.dll' or the code will not work.
Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
Tutorial Link
https://guidedhacking.com/threads/external-internal-pattern-scanning-guide.14112/
How long you been coding/hacking?
1 month
Coding Language
C++
I'm fairly new to game hacking, and am currently working on understanding pattern scanning. I got the signature scan functions Rake wrote working on Assault Cube, so I thought I'd try and use them with CS GO as well.

I am scanning for the localPlayer address in cs go, and the pattern is found just fine. However, it is consistently at the wrong address.

Initially, the address was way off, and I found I was able to get it closer by using uintptr_t instead of char* when scanning for the pattern.

However, the address is still off by a fair bit, despite finding the pattern every time.

I know that the function isn't finding multiple patterns, as I modified my function to print out each match it finds, and it only printed out one.

These are the only things I have tried, as I know the pattern scanner works properly, but I'm not sure why it's returning the wrong address.

Any other ideas of possible sources of error?

Example:

Real localPlayer address: 0x66b6f690
Obtained localPlayer address: 0x58853494

Difference of : 0x66b6f690 - 0x58853494 = 0xE31C1FC

Obviously specific addresses don't matter since they change, but the error is usually around this size even after restarting so maybe it's a helpful example.

Don't worry about the comments. I just put them there to remind me to look into them once I have the main issue solved.

dllmain.cpp:
// dllmain.cpp : Defines the entry point for the DLL application.
#include <Windows.h>
#include "ntdll.h"
#include "pScan.h"



DWORD WINAPI HackThread(HMODULE hModule)
{
    AllocConsole();
    FILE* f;

    freopen_s(&f, "CONOUT$", "w", stdout);
    uintptr_t modBaseAddr = (uintptr_t)GetModuleHandle(L"client.dll");
 

    std::cout << "modBaseAddr : " << std::hex << modBaseAddr << std::endl;
    uintptr_t localPlayer = *(uintptr_t*)(modBaseAddr + 0xD3AC5C); // pointer arithmetic is necessary even if they're the same type. Why?
    uintptr_t localPlayerAddr = ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");
    // why not just use GetModuleHandle? Stealth

    std::cout << "here?\n";

   
   
    std::cout << "localPlayerAddress: " << std::hex << (DWORD)localPlayerAddr << std::endl;
    std::cout << "Real LocalPlayer : " << (DWORD)localPlayer << std::endl;

    uintptr_t health1 = *(uintptr_t*)(localPlayer + 0x100);
   uintptr_t health2 = *(uintptr_t*)(localPlayerAddr + 0x100);

    std::cout << "RealPlayerHealth : " << std::dec << health1 << std::endl;
    std::cout << "LocalPlayerHealth : " << health2 << std::endl;

    while (true) // not having a while loop fucks the program. Idk why.
    {
        if (GetAsyncKeyState(0x39) & 1)
            break;
    }
    fclose(f);
    FreeConsole();
    FreeLibraryAndExitThread(hModule, 0);
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)HackThread, hModule, 0, nullptr));
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
pScan.cpp:
#include "pScan.h"


uintptr_t ScanBasic(const char* pattern, const char* mask, uintptr_t begin, intptr_t size)
{
    int n;
    intptr_t patternLen = strlen(mask);
   
    for (int i = 0; i < size; i++)
    {
        bool found = true;
        for (int j = 0; j < patternLen; j++)
        {
            //std::cout << mask[j] << std::endl; j was always x never ?
           
            if (mask[j] != '?' && pattern[j] != *(char*)(begin + i + j))
            {
                found = false;
                break;
            }
           
        }
        if (found)
        {
            std::cout << "ScanBasic begin : " << begin << std::endl;
            std::cout << "ScanBasic i : " << i << std::endl;
            std::cout << "ScanBasic return: " << *(uintptr_t*)(begin + i) << std::endl;

            return  *(uintptr_t*)(begin + i); // start of pattern
        }
    }
    return 0;
}

uintptr_t ScanInternal(const char* pattern, const char* mask, uintptr_t begin, intptr_t size)
{
    uintptr_t match{0};
    MEMORY_BASIC_INFORMATION mbi{};

    for (uintptr_t curr = begin; curr < begin + size; curr += mbi.RegionSize)
    {
        if (!VirtualQuery((LPCVOID)curr, &mbi, sizeof(mbi)) || mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS)
            continue;
        //std::cout << "MBI Region Size : " << mbi.RegionSize << std::endl;
        match = ScanBasic(pattern, mask, curr, mbi.RegionSize); // used begin instead of curr

        if (match)
        {
            std::cout << "match != nullptr\n";
            break;
        }
    }
    if (!match)
    {
        std::cout << "returning nullptr\n";
    }
    return match;
}

char* TO_CHAR(wchar_t* string)
{
    size_t len = wcslen(string) + 1;
    char* c_string = new char[len];
    size_t numCharsRead;
    wcstombs_s(&numCharsRead, c_string, len, string, _TRUNCATE);
    return c_string;
}

PEB* GetPEB()
{
    #ifdef _WIN64
        PEB* peb = (PEB*)__readgsword(0x60);

    #else
    PEB* peb = (PEB*)__readfsdword(0x30);
    #endif

    return peb;
}

LDR_DATA_TABLE_ENTRY* GetLDREntry(std::string name)
{
    LDR_DATA_TABLE_ENTRY* ldr = nullptr;

    PEB* peb = GetPEB();

    LIST_ENTRY head = peb->Ldr->InMemoryOrderModuleList;

    LIST_ENTRY curr = head;

    while (curr.Flink != head.Blink) // this works because curr = head is the start and h.Blink is used as condition
    {
        LDR_DATA_TABLE_ENTRY* mod = (LDR_DATA_TABLE_ENTRY*)CONTAINING_RECORD(curr.Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);

        if (mod->FullDllName.Buffer) // wonder why he used FullDllName here rather than BaseDllName
        {
            char* cName = TO_CHAR(mod->BaseDllName.Buffer);

            if (!_stricmp(cName, name.c_str()))
            {
                ldr = mod;
                break;
            }
            delete[] cName;
        }
        curr = *curr.Flink;
    }
    return ldr;
}

uintptr_t ScanModIn(const char* pattern, const char* mask, std::string modName)
{
   
    LDR_DATA_TABLE_ENTRY* ldr = GetLDREntry(modName);
    std::cout << "starting base addr : " << std::hex << (void*)ldr->DllBase << std::endl;
    uintptr_t match = ScanInternal(pattern, mask, (uintptr_t)ldr->DllBase, ldr->SizeOfImage);
    std::cout << std::hex << "First Match: " << match << std::endl;
    match += 0x3; // does not like ptr arithmetic with these
    match += 0x4;
    std::cout << "match: " << std::hex << match << std::endl;
    return match;
}
 

BDKPlayer

No hack no life
Dank Tier VIP
Dank Tier Donator
Oct 31, 2013
380
13,688
36
I slapped client.dll in IDA to see where your pattern leads me. The result is:

1600104343188.png


8D 34 85 58 AC D3 10 <-- so you want the green bytes of the marked line in IDA

so what you want to do is:
C++:
uintptr_t localPlayerCodeAddress= ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

//localPlayerCodeAddress now the address where this CODE is "LEA..." which is the marked line. You acutally want the 4 bytes that follow after the bytes for the instruction
//if this is not the case you messed up something with your pattern scanning code


int32_t localPlayerOffset = *(int32_t*)(localPlayerCodeAddress+3);  //This gives you the green bytes (little endian is no problem here)
localPlayerOffset += 0x4; //finally you want to add 4 because that value is 4 less than the value you gave as "real localplayer"
int32_t reallocalplayer = modBaseAddr + localPlayerOffset
Edit: I didn't test it but atleast this should enable you to see where things go wrong for you :)
 
Last edited:

BDKPlayer

No hack no life
Dank Tier VIP
Dank Tier Donator
Oct 31, 2013
380
13,688
36
I did double check in csgo. This should work. I thought you had some sig for an offset. Im tired :p (the change is that you don't need the client.dll address to localplayler.

C++:
uintptr_t localPlayerAddr = (uintptr_t)Pattern::Scan("client.dll", "\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx");
int32_t localPlayer = *(int32_t*)(localPlayerAddr + 3);
localPlayer += 0x4;
gn8 :*
 

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
I slapped client.dll in IDA to see where your pattern leads me. The result is:

View attachment 11819

8D 34 85 58 AC D3 10 <-- so you want the green bytes of the marked line in IDA

so what you want to do is:
C++:
uintptr_t localPlayerCodeAddress= ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

//localPlayerCodeAddress now the address where this CODE is "LEA..." which is the marked line. You acutally want the 4 bytes that follow after the bytes for the instruction
//if this is not the case you messed up something with your pattern scanning code


int32_t localPlayerOffset = *(int32_t*)(localPlayerCodeAddress+3);  //This gives you the green bytes (little endian is no problem here)
localPlayerOffset += 0x4; //finally you want to add 4 because that value is 4 less than the value you gave as "real localplayer"
int32_t localplayer = modBaseAddr + localPlayer
Edit: I didn't test it but atleast this should enable you to see where things go wrong for you :)
So far it doesn't work, but I'm going to test it out more and let you know of any questions I have. What you added at least makes a lot more sense and reduced the abstraction by quite a bit.

Thank you for this. I have class in a bit but I'll look further into it and see why it's going wrong now.

Another question: when searching for a sequence of bytes in IDA Pro, what format should the binary string be in? Should I replace the wildcard "?"'s with 0's or just leave them? Should I have spaces in between? I'm trying to replicate your search for the sequence of bytes.
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
Your confusion is that you think you're scanning for the address of the localplayer object. That's not how it works.

From our pattern guide:

You pattern scan for CODE, not DATA
Meaning, your signature should be for assembly instructions which are converted into bytes. Like "mov eax, [esi]". You do not pattern scan for the health integer 100. You pattern scan for the code which accesses this address. When you pattern scan returns the resulting address of the matching instructions, you then read the memory in that area where the address is hardcoded into the instructions. Or you hook and pull the value out of register. If you are pattern scanning for DATA you will get false positives. There are fringe cases when you will scan for DATA but that's rare.

PatternScan returns the address of the instruction, you have to index past that instruction to get to the address of the argument which contains the hardcoded offset/address, you read from that address to get the address of the local player
 

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
Your confusion is that you think you're scanning for the address of the localplayer object. That's not how it works.

From our pattern guide:

You pattern scan for CODE, not DATA
Meaning, your signature should be for assembly instructions which are converted into bytes. Like "mov eax, [esi]". You do not pattern scan for the health integer 100. You pattern scan for the code which accesses this address. When you pattern scan returns the resulting address of the matching instructions, you then read the memory in that area where the address is hardcoded into the instructions. Or you hook and pull the value out of register. If you are pattern scanning for DATA you will get false positives. There are fringe cases when you will scan for DATA but that's rare.

PatternScan returns the address of the instruction, you have to index past that instruction to get to the address of the argument which contains the hardcoded offset/address, you read from that address to get the address of the local player
Oh okay. I thought I had understood that I first read it but clearly not. Makes much more sense now.
Thank you!
 

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
I slapped client.dll in IDA to see where your pattern leads me. The result is:

View attachment 11819

8D 34 85 58 AC D3 10 <-- so you want the green bytes of the marked line in IDA

so what you want to do is:
C++:
uintptr_t localPlayerCodeAddress= ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

//localPlayerCodeAddress now the address where this CODE is "LEA..." which is the marked line. You acutally want the 4 bytes that follow after the bytes for the instruction
//if this is not the case you messed up something with your pattern scanning code


int32_t localPlayerOffset = *(int32_t*)(localPlayerCodeAddress+3);  //This gives you the green bytes (little endian is no problem here)
localPlayerOffset += 0x4; //finally you want to add 4 because that value is 4 less than the value you gave as "real localplayer"
int32_t reallocalplayer = modBaseAddr + localPlayerOffset
Edit: I didn't test it but atleast this should enable you to see where things go wrong for you :)
My main issue right now is that when I perform pointer arithmetic on my localPlayerAddr, it returns 0. I've never had an issue with this before, so I can't tell if this is just some misunderstanding of basic pointer arithmetic, or if something larger is going on.

So:

C++:
uintptr_t localPlayerAddr = ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

int32_t localPlayerOffset = *(int32_t*)(localPlayerAddr + 3);
// localPlayerOffset = 0;

localPlayerOffset += 0x4;
// localPlayerOffset is now == 4;

int32_t localPlayer2 = modBaseAddr + localPlayerOffset;
// localPlayer2 = modBaseAddr + 0x4
I'd figure that we typecast it to an int32_t ptr so that when we add to it, it adds the appropriate amount of bytes. Then, we dereference it from there, in order to get the address with the added value. Correct?
 

Kekz

Maybe Pasting
Dank Tier Donator
Nobleman
Jan 10, 2020
137
3,668
12
I'd figure that we typecast it to an int32_t ptr so that when we add to it, it adds the appropriate amount of bytes. Then, we dereference it from there, in order to get the address with the added value. Correct?
I think you're confused on when pointer arithmetic is actually applied. Casting to int32_t* doesn't "trigger" any pointer arithmetic, since we add 3 first (still on the uintptr_t, which if you look at its definition is just an unsigned int) and then cast it and immediately dereference it. So adding 3 to the uintptr_t does exactly just that, move up by 3 bytes. If you were to cast it first to int32_t* and then add 3, it would "advance" by 3 int32_t pointers -> 3 * 4 = 12 Bytes. I'm not entirely sure if this is even your problem, but from reading your posts I think there is still a little confusion on this topic.
 

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
I think you're confused on when pointer arithmetic is actually applied. Casting to int32_t* doesn't "trigger" any pointer arithmetic, since we add 3 first and then cast it and immediately dereference it. So adding 3 to the uintptr_t does exactly just that, move up by 3 bytes. If you were to cast it first to int32_t* and then add 3, it would "advance" by 3 int32_t pointers -> 3 * 4 = 12 Bytes. I'm not entirely sure if this is even your problem, but from reading your posts I think there is still a little confusion on this topic.
Oh, okay. I thought the typecast int32_t* was applied, localPlayerAddr was incremented by 12 bytes, and then dereferenced. Thanks for the clarification.
 

Kekz

Maybe Pasting
Dank Tier Donator
Nobleman
Jan 10, 2020
137
3,668
12
Oh, okay. I thought the typecast int32_t* was applied, localPlayerAddr was incremented by 12 bytes, and then dereferenced. Thanks for the clarification.
That's what the brackets are for.
C++:
// Add 3 to uintptr_t, then cast to int32_t* (=> 3 "Bytes")
int32_t localPlayerOffset = *(int32_t*)(localPlayerAddr + 3);
// vs  Cast to int32_t* and then add 3 (=> 12 Bytes)
int32_t localPlayerOffset = *(int32_t*)(localPlayerAddr) + 3; // brackets around localPlayerAddr don't do anything special here
 
  • Like
Reactions: SPQR

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
That's what the brackets are for.
C++:
// Add 3 to uintptr_t, then cast to int32_t* (=> 3 "Bytes")
int32_t localPlayerOffset = *(int32_t*)(localPlayerAddr + 3);
// vs  Cast to int32_t* and then add 3 (=> 12 Bytes)
int32_t localPlayerOffset = *(int32_t*)(localPlayerAddr) + 3; // brackets around localPlayerAddr don't do anything special here
That makes a lot more sense. Was wondering why we would typecast like that with variables of the same type.

Do you have an idea of why the resulting address would return 0? It still seems reasonable that an address should result from the operation.
 

Kekz

Maybe Pasting
Dank Tier Donator
Nobleman
Jan 10, 2020
137
3,668
12
That makes a lot more sense. Was wondering why we would typecast like that with variables of the same type.

Do you have an idea of why the resulting address would return 0? It still seems reasonable that an address should result from the operation.
Nope.
I have never used this signature / offset myself, but I just tried it and am not getting 0 (idk if this value is correct, as I said I never used it)
Unbenannt.PNG

Open Cheat Engine's memory view, set a breakpoint on your Pattern scan result and look at the location.
Unbenannt.PNG

If you look at the underlined bytes (those are the ones we hide with our wildcards '?'), that's exactly what localPlayerOffset contains (keep in mind endianess).
If you are getting 0 then those 4 bytes would need to be 0, which doesn't really make sense. Maybe your pattern scan is messing up.
Just follow along manually with what your code is doing, step by step and you should hit a point where something is wrong.

Edit:
Or maybe my pattern scan messed up, since apparently I have a different result than BDKPlayer? I just confused myself. I'm going to sleep now.
Edit2:
Nevermind, I think he might be just using a slightly older IDA database since I got it directly from CheatEngine
 
  • Like
Reactions: SPQR

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
This is your code:

C++:
uintptr_t localPlayerAddr = ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

int32_t localPlayerOffset = *(int32_t*)(localPlayerAddr + 3);
// localPlayerOffset = 0;

localPlayerOffset += 0x4;
// localPlayerOffset is now == 4;

int32_t localPlayer2 = modBaseAddr + localPlayerOffset;
localPlayerOffset is not an offset. It's the absolute address. You're adding it to a module base address for no reason

View this source code to learn about dumper config files, that 'relative' makes it subtract the modbase before it writes it to the dumped file
Guided Hacking Offset Dumper - GH Offset Dumper
 
Last edited:
  • Like
Reactions: SPQR

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
Nope.
I have never used this signature / offset myself, but I just tried it and am not getting 0 (idk if this value is correct, as I said I never used it)
View attachment 11821
Open Cheat Engine's memory view, set a breakpoint on your Pattern scan result and look at the location.
View attachment 11822
If you look at the underlined bytes (those are the ones we hide with our wildcards '?'), that's exactly what localPlayerOffset contains (keep in mind endianess).
If you are getting 0 then those 4 bytes would need to be 0, which doesn't really make sense. Maybe your pattern scan is messing up.
Just follow along manually with what your code is doing, step by step and you should hit a point where something is wrong.

Edit:
Or maybe my pattern scan messed up, since apparently I have a different result than BDKPlayer? I just confused myself. I'm going to sleep now.
Edit2:
Nevermind, I think he might be just using a slightly older IDA database since I got it directly from CheatEngine
I restarted my PC and don't get 0 as the value anymore. Now I just get an incorrect address 🙃

I debugged and went through step by step, but still not sure where the error is.

Thank you to everyone for all the help. I'm going to take a break and look at it again later.
 

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
if it wasn't clear the pseudo code should be:

C++:
uintptr_t sigLocation = ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

int32_t localPlayerAddr = *(int32_t*)(sigLocation + 3);

int32_t healthAddr = localPlayerAddr + healthOffset;

std::cout << "health = " << *(int*)healthAddr << std::endl;
that should print 100

If it doesn't work, zip up your project and I will fix it

If you want our help, please zip up your Visual Studio project using SolZipper and attach it in a reply. SolZipper removes the files we don't need and includes the ones we do, preserving the project settings so they are identical to the ones you are using. This allows us to easily review and fix your project with minimal effort.

 
  • Like
Reactions: SPQR

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
if it wasn't clear the pseudo code should be:

C++:
uintptr_t sigLocation = ScanModIn("\x8D\x34\x85\x00\x00\x00\x00\x89\x15\x00\x00\x00\x00\x8B\x41\x08\x8B\x48\x04\x83\xF9\xFF", "xxx????xx????xxxxxxxxx", "client.dll");

int32_t localPlayerAddr = *(int32_t*)(sigLocation + 3);

int32_t healthAddr = localPlayerAddr + healthOffset;

std::cout << "health = " << *(int*)healthAddr << std::endl;
that should print 100
I think the pseudocode should also add 4 to account for dwLocalPlayer's extra value from hazedumper, but otherwise yes I think that portion of my code follows that.
I think I'm messing up the representation of the addresses somehow. I'll have to look into pointers/addresses again just to be sure.

If it doesn't work, zip up your project and I will fix it
I'm going to think this problem over for a few more days, since solving it would be all the more satisfying if I did it (somewhat) by myself. But, if I can't get it and you're still willing I would definitely appreciate that.
 

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
@Rake I figured it out!

When I switched my Signature Scan functions to uintptr_t from the char* version you gave, I ended up returning the wrong address from my ScanBasic function, as I was returning
*(uintptr_t*)(begin + i) rather than (uintptr_t)(begin + i). Figured that out after I compared the return addresses for the char*, which I knew worked and gave a correct address for assault cube, with my (uintptr_t*)(begin + i) address.

From there, the other issue was how I added the last 4 bytes.

Incorrect Addition of Extras:
localPlayerOffset += 4;
is so much different from
Correct Addition of extra bytes:
localPlayerOffset = *(uintptr_t*)(localPlayerOffset + 0x4);
which after thinking about it should have been so painfully obvious.


After I made those changes, I now get the correct address.

Except, I don't fully understand the logic of why it went wrong. Pretty much just deduced that from the correct code and trial and error.

What is happening when calculating the address of *(uintptr_t*)(localPlayerOffset + 0x4)? I know you have resources on it, so I'll definitely check those out right now, but why is the difference in addresses so large? I'd figure there'd be a minor difference, since casting to a ptr then adding adds the byte size rather than the integer, but the new addresses I'm getting are so much larger than I would expect.

Just a concept I'm having a hard time understanding.

Edit:
Looked into it, and I think I have an idea of where I'm misunderstanding how pointers work:
Is the reason there are large gaps from just adding 4 bytes to the pointer due to the fact that we're just adding to get a pointer that points to a different place in memory? i.e. I shouldn't assume there should be any consistency from increasing a pointer's address by a small amount, since the pointer is just pointing to an address, and so dereferencing it doesn't guarantee that I've moved any predictable distance?
 
Last edited:

Rake

Cesspool Admin
Administrator
Jan 21, 2014
12,061
78,998
2,370
idk where exactly the confusion is but:
  1. scan for pattern, store the return value as an intptr_t
  2. result = result + offset
  3. result = *(intptr_t*)result
  4. result = result + extra
  5. relative offset = result - modBaseAddr

C++:
void SigData::Scan(ProcEx proc)
{
    //Scan for the pattern
    intptr_t result = (intptr_t)Pattern::Ex::ScanMod((char*)comboPattern.c_str(), mod);

    //first offset is relative to pattern location, different than FindDMAAddy, you must add offset first, then RPM
    if (offsets.size() != 0)
    {
        for (auto o : offsets)
        {
            result = result + o;
            ReadProcessMemory(proc.handle, (BYTE*)result, &result, sizeof(o), NULL);
        }
    }

    //offset into the resulting address, if necessary
    if (extra)
    {
        result = result + extra;
    }

    //if a relative offset, get the relative offset
    if (relative)
    {
        result = result - (intptr_t)mod.modEntry.modBaseAddr;
    }
}
the whole integer vs pointer concept is super simple once you understand it, it's just one of those things that is kinda confusing in the beginning
 
Last edited:

SPQR

Dank Tier Donator
Full Member
Apr 6, 2020
14
328
0
idk where exactly the confusion is but:
  1. scan for pattern, store the return value as an intptr_t
  2. result = result + offset
  3. result = *(intptr_t*)result
  4. result = result + extra
  5. relative offset = result - modBaseAddr

C++:
void SigData::Scan(ProcEx proc)
{
    //Scan for the pattern
    intptr_t result = (intptr_t)Pattern::Ex::ScanMod((char*)comboPattern.c_str(), mod);

    //first offset is relative to pattern location, different than FindDMAAddy, you must add offset first, then RPM
    if (offsets.size() != 0)
    {
        for (auto o : offsets)
        {
            result = result + o;
            ReadProcessMemory(proc.handle, (BYTE*)result, &result, sizeof(o), NULL);
        }
    }

    //offset into the resulting address, if necessary
    if (extra)
    {
        result = result + extra;
    }

    //if a relative offset, get the relative offset
    if (relative)
    {
        result = result - (intptr_t)mod.modEntry.modBaseAddr;
    }
}
the whole integer vs pointer concept is super simple once you understand it, it's just one of those things that is kinda confusing in the beginning
Yeah, I did some testing on where I was misunderstanding and I think I get it now.

Thank you and everyone else in this thread for all the help. This forum's pretty cool.
 
  • Like
Reactions: omegaweapontmod
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods