LoadLibraryW / BNSBoost

A simple launcher for Blade & Soul patches. Working as of the Fire and Blood game update.
GNU General Public License v3.0
20 stars 9 forks source link

[Not an issue] I made an alternative version of BNSBoost #3

Closed temghost03ajfksdf closed 7 years ago

temghost03ajfksdf commented 7 years ago

Hi again @Xyene,

I ported your code to use a fake steam_api.dll as an entry point, so that it gets automatically loaded into NCLauncher's address space. This is nice because it doesn't require the use of an injector, or a UI for configuration. Also by the very nature of the entry point, it is no longer necessary to programatically search for NCLauncherR.exe's location.

I also tried to make it as game-agnostic as possible by giving the user the option to specify their own custom command line arguments in an init.ini file. This is assuming that it is used with a launcher that also imports steam_api.dll, is vulnerable to IAT manipulation and uses the same APIs, etc., though with a little work it could be made compatible with a wide variety of game launchers.

All of the changes I've made have been documented in the README.

You can find it here https://github.com/zeffy/bnsboost-steam_api.dll

If you want to use it as a base for future updates to BNSBoost, or want to use any of the source code I added, by all means feel free. Right now it doesn't make use of any secure string functions, so that will probably be what I work on next.

Just thought I would let you know what I did with your already awesome project. :)

Peace. :v:

Xyene commented 7 years ago

Cool!

The main reason I opted for injecting a DLL rather than hijacking one is that it's tricky to do anything safely in DllMain, see this, this and this... you get the idea. Strictly speaking, the VirtualProtect call in the IAT hooking is unsafe and may or may not cause problems. The moment the hook becomes nontrivial and has extra library dependencies it must use LoadLibrary, in which case using DllMain is guaranteed to deadlock. Though BNSBoost currently does not do anything unsafe apart from VirtualProtect, having users report unreproducible deadlocks doesn't sound like a load of fun, either now or in the future 😁

It'd be even more so a concern with something as generic as a Steam hook, where anyone may use it without knowledge of DllMain restrictions. As you've probably seen, BNSBoost writes raw bytes of a function that initializes the hook into the memory of the target process — this runs outside of the DLL loader lock, so anything InjectMain does is absolutely safe from its perspective.

You could circumvent this by applying the hooks outside of the loader lock (SteamAPI_Init?) but by that point the game could have run many CreateFileW calls, and furthermore load more modules with LoadLibraryW. In particular, file verification in the NCLauncher is done by NCUpdate.dll, which is loaded only after you've passed the login dialog... so unless you have your LoadLibraryW hook in place by then, you'll have to enumerate all modules on a SteamAPI_Init call and apply your hooks at that time — and pray NCUpdate.dll hasn't done any verification yet.

I think at the end it ends up very tricky to do right, but the idea of a generic Steam hook is a cool one.

temghost03ajfksdf commented 7 years ago

Very good points about the deadlocking. I was aware of that being an issue with hijacked dlls, but since it has been working flawlessly for me during hours of testing, I wasn't too worried about it.

However, I will definitely look into installing the hooks during one of the SteamAPI_* calls rather than DllMain. That's a really good idea as long as the calls are made fairly early in the launcher's lifetime, as you mention.

You are right though, this is tricky to get right, but I welcome the challenge. :)

Xyene commented 7 years ago

Good luck 😄

If an approach like this worked reliably, I'd be up for using it in BNSBoost simply because it's, well, simpler. From a UI perspective, it'd still require detecting the launcher path to programmatically add in the patched steam_api.dll (users could add in the DLL themselves, but it's better UX if they don't have to), but I don't think that's really that big a hassle.

Unrelated, but if you'd like to chat on something more convenient than Github issues, feel free to shoot me an email.

temghost03ajfksdf commented 7 years ago

So after quickly looking through and debugging NCLauncherR.exe, it looks like all of the functions that reference the SteamAPI_* functions are dead code, probably remnants of launcher code from other NCsoft games that are actually on Steam.

So that's a no-go, but I may be able to come up with another solution to potential deadlocking (I've heard mixed results regarding using CreateThread?). Or something else, we'll see.

Edit: According to this, CreateThread can be used from within DllMain as long as you don't try to synchronize with it at all, which I don't think should be an issue with something like this. So I'm going to go ahead and move all the hooking logic into a separate thread. That should completely eliminate any potential deadlocking, I believe.

Once I get that implemented, I'm going to see if I can add some kind of self-protection logic in CreateFileW to prevent getting overwritten with the real steam_api.dll even if it isn't backed up to the _original folder, which should vastly improve the ease of installation.

temghost03ajfksdf commented 7 years ago

Done. Any potential deadlock issues due to VirtualProtect should now be resolved on my fork.

I think both projects can co-exist nicely, though. Your UI provides a far more accessible way for people who may be novices to this, so that they can still use it effectively. My fork can provide "advanced" users with more finely grained options like the custom command line args, etc. (other features planned as well). I look forward to seeing how both projects evolve! :)

(btw, as I said in the OP you are absolutely more than welcome to cherry-pick anything you want from my fork and integrate it into BNSBoost if you choose to.)

Xyene commented 7 years ago

If Raymond says it's so, it must be so 😄

Likewise, if you see anything nice in BNSBoost, feel free to port it over. If you'd like to do stuff on this project, I'm fine with giving you write access to save the hassle of PRs.

As an aside, I think I'll be maintaining this for at least a while, as BNSBuddy has opted for the approach of shimming auth tokens, which feels like climbing the security fencepost rather than walking around it. I'll be launching my game like this rather than with a self-generated token, anyway.

temghost03ajfksdf commented 7 years ago

If you don't mind, that would be really cool. I could definitely help work on this along with my fork. I can add you to my fork too if you like. Also, if you use Steam you can add me (if you want), so we can communicate less awkwardly: click for image of my url, expires in 24hr.

And yes, I totally agree. While emulating the authentication protocol is really neat in theory, it seems like a terrible long term solution considering how easy it would be for NCSoft to break it again if they wanted to, vs. how long it would take to reverse engineer the protocol from scratch again.

Also, unless it is emulated with 100% accuracy (indistinguishable from official launcher), it would most likely be trivial for them to hand out a mass ban to people using such techniques. I doubt they would resort to such measures, but who knows.

Regardless, BNSBoost is a much, much better solution IMO.

Xyene commented 7 years ago

Grrr, I made a Steam account but can't add you since I haven't spent $5 on it. Perhaps you'd be able to add me though? If not, I have a Slack team set up for a project not entirely unrelated to this, so you could join it here and send me a DM.

I've given you access rights on this repository.

temghost03ajfksdf commented 7 years ago

I sent you an invite on Steam, hope it worked! Also added you to my fork :)