Ripper99-x / CS2-Internal

58 stars 10 forks source link

Pattern #1

Closed dethlux closed 4 months ago

dethlux commented 4 months ago

What is the name of this pattern "48 8B ?? ?? ?? ?? ?? 48 89 ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 89 ?? ?? ?? 89 74" ? Found is d3d.h line 215

Ripper99-x commented 4 months ago

I don't have any descriptive name for it at the moment.

If you are interested in how you can find it if the sig ever break, just let me know in here and I'll tell you.

dethlux commented 4 months ago

Thank you! I like the uniqueness in this cheat, coding wise.

SMSum commented 4 months ago

Gonna re-open this, working on a similar project. Was originally using the built in CreateHook and HkPresent from GameOverlayRender64.dll but I am curious, (the sig is broken so idk) but are you just getting the swapchain from the HkPresent?

Ripper99-x commented 4 months ago

The sig for SwapChain is not broken atm. You can use it, get the relative address, substract 0x28, deference, and you are have an instance of SwapChain class.

DO NOT hook it with ShadowVMT or Simple VMT, you gonna get insta banned.

Ripper99-x commented 4 months ago

but are you just getting the swapchain from the HkPresent?

No, I do a pattern scan in gameoverlayrenderer64.dll. I get the relative address, substract 0x28, deference it twice, and I am at virtual table entry.

Then I get the address by copying the value of 8th index from the v-table which is Present Function.

SMSum commented 4 months ago

Gotcha, I said the sig was broken because when I tried searching for it in IDA I came up dry. Were you using Fusion or SigMaker?

Ripper99-x commented 4 months ago

I didn't used any of those. I just did the sig by myself.

You sure you searched for it in the correct DLL ?

SMSum commented 4 months ago

You sure you searched for it in the correct DLL ?

Yes haha, I guess I will do some digging around to find it, no worries.

DO NOT hook it with ShadowVMT or Simple VMT, you gonna get insta banned.

I assume shadowVMT is detected due to changing pointers to the fake VT? Meerly a thought, but if you placed your shadow VTable outside of usermode memory address range, then VAC scan shouldn't be able to find out if they're reading, but I dont know if they just read or compare pointers/vtables

Ripper99-x commented 4 months ago

Once you deference the address AOB scan finds - 0x28. You'll be at SwapChain instance.

If you modify the swapchain instance to point to your own v-table aka Shadow VMT, they somehow detect it.

The simple VMT hook is just changing the pointer at index 8 to your own, but I m 99% sure it's detected aswell, cause you modify a Read Only page.

SMSum commented 4 months ago

Once you deference the address AOB scan finds - 0x28. You'll be at SwapChain instance.

If you modify the swapchain instance to point to your own v-table aka Shadow VMT, they somehow detect it.

The simple VMT hook is just changing the pointer at index 8 to your own, but I m 99% sure it's detected aswell, cause you modify a Read Only page.

Gotcha, makes sense. I figured, I assume that is the reason you read memory and then detour to intercept Present instead of blatantly swapping pointers?

Ripper99-x commented 4 months ago

If you swap pointers inside the virtual table directly, they'll know something is wrong, cause the virtual table has Read Only permissions + you redirect a function outside a legit module. For example, the function at index 8, if you get the address like I do, will always have the first instruction as jmp -> RivaTurner(if you use MSI AfterBurner) or jmp -> GameOverlayRenderer64.dll because it's hooked already as the game starts.

Any legit overlay will just detour it cause valve allows it.

And for ShadowVMT, they probably detect(not 100% sure if this is the reason), because it's easy to know where the instance of swapchain is located in the memory, and then just check if it points to a legit module or non backed memory, since you can do like KIERO::BIND does, it finds the address dynamically. So it's easy for Valve aswell to do what and check if it's changed, and if it is, insta ban, since no legit 3rd overlay will blatantly swap the ptr, instead of detouring.

SMSum commented 4 months ago

If you swap pointers inside the virtual table directly, they'll know something is wrong, cause the virtual table has Read Only permissions + you redirect a function outside a legit module. For example, the function at index 8, if you get the address like I do, will always have the first instruction as jmp -> RivaTurner(if you use MSI AfterBurner) or jmp -> GameOverlayRenderer64.dll because it's hooked already as the game starts.

Any legit overlay will just detour it cause valve allows it.

And for ShadowVMT, they probably detect(not 100% sure if this is the reason), because it's easy to know where the instance of swapchain is located in the memory, and then just check if it points to a legit module or non backed memory, since you can do like KIERO::BIND does, it finds the address dynamically. So it's easy for Valve aswell to do what and check if it's changed, and if it is, insta ban, since no legit 3rd overlay will blatantly swap the ptr, instead of detouring.

This is big brained, I haven't looked into other overlays to see how they get away with it.

SMSum commented 4 months ago

Follow up, I was re-reading. Is there a specific reason you use memcpy instead of just dereferencing it normally? To my knowledge they end up doing the same thing, we always know the memory is valid, so it feels like wasted CPU cycles checking VirtualQuery, the page access, if its out of range, etc 3x for each dereference.

*reinterpret_cast<DWORD64*>(pSwapChain);

Ripper99-x commented 4 months ago

You mean why I use memcpy in the ReadMemoryInternal function ?

SMSum commented 4 months ago

You mean why I use memcpy in the ReadMemoryInternal function ?

No. When you are getting the Present that you cast into oPresent, I dont understand why you're calling your ReadMemoryInternal 3x when just doing this results in the same thing. Unless I am somehow mistaken, neither write to memory. Just seems like a lot of wasted cycles to check what we already know is safe + valid

DWORD64 derefFirst = reinterpret_cast<DWORD64>(pSwapChain); DWORD64 derefSecond = reinterpret_cast<DWORD64>(derefFirst); DWORD64 derefFinal = reinterpret_cast<DWORD64>(derefSecond + 0x40);

Ripper99-x commented 4 months ago

Yeah, now I get it.

You are quite right, but performance wise, you won't see any difference, the hooking function is called once.

I used the read function because if you inject too early, it will crash since the memory is not valid yet if you try to deference. But since I found the sweet spot of when to inject, that read memory call can be removed.