Skip to content
This repository has been archived by the owner on Dec 22, 2023. It is now read-only.

Decrease size of ScintillaNET DLL #26

Closed
BetaOptimization opened this issue Jun 11, 2015 · 7 comments
Closed

Decrease size of ScintillaNET DLL #26

BetaOptimization opened this issue Jun 11, 2015 · 7 comments

Comments

@BetaOptimization
Copy link

Compressing the SciLexer DLLs using gzip will decrease their size by about half and hence reduce the size of the final DLL. Implementing this requires gzipped files to be embedded and a minor change to the code, line 862 in Scintilla.cs:GetModulePath()

                            var resource = string.Format(CultureInfo.InvariantCulture, "ScintillaNET.{0}.SciLexer.dll.gz", (IntPtr.Size == 4 ? "x86" : "x64"));
                            var resourceStream = typeof(Scintilla).Assembly.GetManifestResourceStream(resource); // Don't close the resource stream
                            using (var gzipStream = new System.IO.Compression.GZipStream(resourceStream, System.IO.Compression.CompressionMode.Decompress))
                            using (var fileStream = File.Create(modulePath))
                                gzipStream.CopyTo(fileStream);
@dspwhite
Copy link

Thanks for the info. This could come in handy - I like to create fully portable apps with no installation necessary, and a single self-contained executable file would be preferred (like the old Amiga days!). So this technique will bode well with that.

It'd be good to see this distributed as standard providing there's negligible loss of performance, or latency when opening the app (any idea in milliseconds of the one-time lag?).

@aolszowka
Copy link

Somewhat related, it looks like the library using using the size of IntPtr to determine the bitness of the process, if you're targeting .NET 4 or higher Environment.Is64BitProcess should be used.

Pretty novel idea to extract the third party library into the Temporary directory, however isn't that also a potential security issue? Essentially you're assigning trust to a binary that is in an untrusted area. Could one not dump a compromised binary into the Temp folder (which all privilege levels for a user have write access to) and then gain the privileges of any executing process that uses this library? IE Application 1 which runs under a limited user account and dumps the "bad dll" into the Temp File at the expected location; Application 2 which runs as an Administrator and uses this library goes to extract the DLL however it's found at that location, not re-extracted or validated an is executed with administrative privileges.

Based on the way the code is written if the filename exists at the extract location its not re-extracted nor validated in any way beyond the name. https://msdn.microsoft.com/en-us/library/windows/desktop/ff919712%28v=vs.85%29.aspx

Perhaps its just an example of the trope "Code execution results in code execution".

@jacobslusser
Copy link
Owner

@aolszowka,

I wasn't aware of the new Environment.Is64BitProcess property. Is there a benefit to using it instead of checking the IntPtr size? Based on what I've read the result is going to be the same, but Environment.Is64BitProcess can also call into IsWow64Process which is likely to be a bit slower.

As for the DLL security, I read the linked article. Thanks, but I'm failing to see how it would be any less secure loading the DLL from the user's Temp folder than any other folder. The article makes it clear that there is a potential security issue loading DLLs, but doesn't suggest that one place is more secure than another. The only reliable way that I'm aware of is to make sure the DLL being loaded matches a predefined hash -- which is not quite something I think I want to get into. I like the idea of users being able to specify alternative SciLexer DLLs. It was a common practice in ScintillaNET v2.x when users wanted to use a more recent version of SciLexer.dll than was official supported by ScintillaNET.

If security is a concern for any users I would encourage them to use the Scintilla.SetModulePath API as described in Using a Custom SciLexer.dll wiki article. That way they can do any hash checking and explicit path loading if they want.

@aolszowka
Copy link

@jacobslusser

RE: Environment.Is64bitProcess; Unsure to be honest, I think it's probably just a bit clearer when reading the code. Looking at the implementation in ILSpy for the .NET 4.0 it actually simply returns true or false depending on what version of the mscorelib.dll gets loaded which makes sense.

RE: DLL Security; I think the logic is that if you had dropped the DLL into somewhere like Program Files/Program Files (x86)/The GAC/The Windows Directory/Any other "secured" location, you had to have Administrative privileges to do so (by default with a box with UAC on), at which point there is no issue because if you had enough privileges to drop the DLL into that location why bother dropping a rouge DLL in there? Simply perform the administrative action you want. Further more if the DLL was shipped right next to your application and it wasn't secured (or the rouge DLL was dropped in there by the end user themselves) they get what they asked for.

In this case dropping the DLL into a location that is writable by any level of privilege (for example a low privileged process running as your user) and then re-executed by another administrative process (same user) that uses the same version of the ScintillaNET library at the escalation of privilege given to that DLL (especially one that may not be the same one shipped with the library) is probably unexpected at least.

I wasn't aware of the ability to set the module path; thats a great work around and probably should be called out if one was paranoid where it'd be a concern.

@jacobslusser
Copy link
Owner

All very good information. The scenario you pointed out is definitely possible. If that is a concern for anyone then I think using Scintilla.SetModulePath is the way to go. Whether the DLL is written/read from the user temp folder or the application folder, they a both subject to potential malicious use as far as I'm concerned. If the user wants the added security of loading and verifying the DLL, using Scintilla.SetModulePath allows them to do that.

Thanks.

jacobslusser added a commit that referenced this issue Jun 11, 2015
In my testing I didn't see any appreciable drop in performance using
GZIP. Not to mention the DLLs only get extracted once. Just in case, I'm
using the fastest form of compression supported by GZIP because
slower/stronger compression didn't yield much difference in the size.
@jacobslusser
Copy link
Owner

@BetaOptimization great tip. Thanks! I've added your suggestion in commit 29fff0c.

@BetaOptimization
Copy link
Author

Very cool, thanks! Also for the lightning quick implementation of issue #25.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants