2

Let's guess in my application I allow to load a DLL with LoadLibrary WIN32. As i don't know the code of that DLL it can be malicious. So my question is, there is some way to tell windows to apply some restrictions to that DLL ( for example disk access, read passwords, or other potential dangerous data read/write accesses ) ?

That way any time that the DLL code is trying to access disk, an exception is generated or the method called return some error. It could be useful to avoid using javascript or other scripts interpretated code instead of compiled & linked & efficient one.

Do exists any kind of similar mechanism that i could use?

ex1: RestrictAccess( GetProcAdress( ... ), size ); // by code memory access

ex2: thread1.loadLibrary( file ); RestrictAccess( thread1 ); // by thread access

etc...

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Tonatiuh
  • 41
  • 5
  • Sandboxes do about that, but I don't know how they work with Windows, and I don't know if you can use them for specific DLLs instead of a whole process. That said, there's no way to prevent an app from prompting for a password (except preventing it from showing windows at all). – zneak Mar 20 '11 at 16:15

4 Answers4

1

There is no simple solution such as an API you can call to restrict a process or a thread.

What IE does in protected mode (on Vista and Windows 7) is to load plug-ins into a separate process at a low integrity level. Processes running in low integrity mode have less access to system resources and are more isolated from higher integrity level processes. You can also set up ACLs on things like file system objects and registry keys that control whether or not low-integrity processes can access them. This limits the amount of damage they can do. This is a form of sandboxing or (depending on how strictly you define it) virtualization.

It's a lot of work to get it right. A low-integrity process can be so restricted that it needs help to do much of anything. When IE launches a protected mode process, it gives it a channel for communicating back to the main IE process. The plug-in can then make requests via this channel to do things like make registry changes and write to the file system. IE considers the requests and if it determines that it should be allowed, the IE process will do it on behalf of the plugin.

Another approach (which can be used to complement the sandboxing) is to require the DLL to be signed with a valid certificate. The signing allows you to have a little more trust in the DLL, because the certificate identifies a responsible party. The signature also ensures that nobody has tampered with the DLL.

Yet another approach is to hook all of the OS API calls you want to restrict. There are libraries for this, but the technique relies on a bit of OS hackery that could break on any update. The idea would be to create a process with some of your code that sets up a hook for each API you want to restrict and then loads the untrusted code and executes it. If the DLL calls a hooked API (e.g., CreateFile), you're code will get called instead, and it can decide whether to return an error or pass the call onto the real OS API. This is difficult because the number of APIs you have to hook can be huge. Also, if the DLL knows that this is the technique in use, there are things it can do to subvert it.

Finally, you can do true sandboxing by not running native code at all. Instead of loading an untrusted DLL, you load code that's been compiled into some intermediate form and interpret it. This gives your interpretter complete control over what the program can do. This is also hard to implement, and it greatly lowers performance.

These are the extremes you have to go through if you're going to run untrusted code.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • Don't rely on hooking. Anything you can hook from user-mode can be bypassed from user-mode, by the simple expedient of including copies of the hooked function. – Ben Voigt Mar 20 '11 at 16:38
1

The typical solution is to only allow plugins in an interpreted language or byte code compiled that can be sandboxed (e.g. Lua). Some operating systems make such restrictions (e.g. iOS and Android), but I don't believe you'll find such features when loading a native Windows DLL.

Judge Maygarden
  • 26,961
  • 9
  • 82
  • 99
  • In some sense every Windows process is a sandbox. It has no power over anything outside of its own process without the help of kernel services which enforce access control checking. (I was going to say, cannot communicate outside the process without kernel help, but then I remembered that isn't true -- shared resources such as CPU cache create a channel for processes to mutually affect each others' timing and that could theoretically be used for communication) – Ben Voigt Mar 20 '11 at 17:14
1

Privileges can be increased on a per-thread basis, using impersonation, but never decreased (since the untrusted code can always do RevertToSelf).

The minimum unit for lower privileges is the process. And yes, there's an API for that: CreateProcessAsUser. You could use pipes to transfer data to/from the untrusted process.

Or you can use DCOM to call methods of an object in a DLL. You can specify the credentials, and then the OS will do the work of setting up a helper process with those credentials and marshaling the data back and forth.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Never heard about that, I've read a bit now... So the order must something like... process = Start process app() codeDLL = loadDLL() thread = createThread(); // in suspended mode SetThreadToken( thread, token ); // token with lower privileges process.revertToSelf(); // documentation says do it after impersonation startThread( thread, codeDLL ); // thread start executing DLL code with low privileges something like that? – Tonatiuh Mar 20 '11 at 17:30
  • @Tonatiuh: The problem with `SetThreadToken` is, as I mentioned, that the malicious code can do a `RevertToSelf` and escape the jail. You need a separate process to prevent that. – Ben Voigt Mar 20 '11 at 17:32
  • I have removed all the privilegies of current thread result = AdjustTokenPrivileges( hToken, TRUE, NULL, 0, NULL, NULL ); ( result == 1 ) but it still allows me to Create a File... what am i doing wrong? there is not TokenPrivilegies that avoids disk modifications? – Tonatiuh Mar 20 '11 at 23:24
  • @Tonatiuh: You aren't listening to me. You cannot hope to restrict a thread, it can just unrestrict itself at will. And no, file creation is not a "privilege", it depends on the access control list set on the directory the file would be created in. – Ben Voigt Mar 20 '11 at 23:27
  • I'm listening, just trying for learning and I found doubts. BTW, In the main question I did, I ask for restricting disk access. In your answer u suggested about privileges, now u say file creation is not a privilege, so if I do that with the thread or even with a separate process, how am I going to get it work? – Tonatiuh Mar 20 '11 at 23:51
1

You can read the names from the DLL file. This way you can be sure what other DLL's it is linked against and what external function (Windows API for example) it uses. You can create a whitelist to only allow your functions to be called from that DLL, this way you have to create wrapper function to everything the plugin can legally access.

vbence
  • 20,084
  • 9
  • 69
  • 118
  • 1
    Nope, the DLL could still use `LoadLibrary` and `GetProcAddress` to call functions that aren't in its import table. Or it could use the `sysenter` instruction to access OS services without the help of another library. – Ben Voigt Mar 20 '11 at 16:44
  • @Ben I specifically said **whitelist** and you answer with two Windows API calls: `LoadLibrary` and `GetProcAddress`, why do you think the OP would whitelist these? – vbence Mar 20 '11 at 16:53
  • 1
    @vbence: What stops them from hard-coding the function pointer for those two APIs, so they don't show up in the import table? – Ben Voigt Mar 20 '11 at 16:57
  • @Ben I admit I have a bit of a white spot there, but i would be surprised if these were fixed addesses. Even if `Kernel32.dll` was obviously loaded before the program you have no way of kowing which segment holds it etc. But then again, I can be wrong. – vbence Mar 20 '11 at 17:03
  • 1
    @vbence: `kernel32.dll` is always loaded into every process, and all processes on the same computer use the same base address. However, it can be randomized at reboot, so a hard-coded address wouldn't work. Nonetheless, it's well known how to find these functions. http://www.google.com/search?q=shellcode+kernel32+base+address – Ben Voigt Mar 20 '11 at 17:06
  • 1
    @vbence: And even if you couldn't find `kernel32.dll` in memory, a malicious DLL could include its own copies of `LoadLibrary` and `GetProcAddress`. – Ben Voigt Mar 20 '11 at 17:07
  • @Ben "malicious DLL could include its own copies of LoadLibrary" only if it first has the ability to read files. Which would require that is already has access to Win API. - In the other hand, the linked code looks quite convincing but I'm sure you can whitelist the address space too somehow. But my OS insight is limited here. – vbence Mar 20 '11 at 17:24
  • 1
    @vbence: But it DOES have access to the Windows native API, if not the Win32 API, by using the `sysenter` instruction. – Ben Voigt Mar 20 '11 at 17:29