Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Databinding to public members with forceren enabled - Allow renaming of XAML/BAML references #48

Open
rollsch opened this issue Jun 3, 2019 · 4 comments
Labels
bug Something isn't working enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed

Comments

@rollsch
Copy link

rollsch commented Jun 3, 2019

Is your feature request related to a problem? Please describe.
If you have XAML Databinding to public members and use ForceRen (because lets assume your project is not a public library so renaming public methods is acceptable) then this will obviously break databinding.

Describe the solution you'd like
I've hacked a solution which extracts all databinding out of the XAML and makes a list of member names. It then adds these names to the list of items to not rename. My solution is very ugly but it works,

This would be great to see added as it allows a high level of obfuscation such as:

      <protection id="rename">
        <argument name="mode" value="decodable" />
        <argument name="renPublic" value="true" />
		<argument name="flatten" value="true" />
      </protection>

But it also doesn't break XAML databinding. I have a very large project and this approach hasn't failed so far.

To do this properly you would rename the XAML however where I hacked my solution in it seemed like quite a bit of work to make it also rename the XAML, instead I just disabled renaming of these members instead.

here is my function which extracts databinding from .cs files

`private void ExtractBinding(MethodDef methodDef, List<IBaseRef> dynBindings)
{
	if (methodDef == null) return;

	if (!methodDef.HasBody) return;
	if (methodDef.Body?.Instructions == null) return;

	Instruction inst0, inst1, inst2, inst3, inst4, inst5;
	for (var index = 3; index < methodDef.Body.Instructions.Count; index++)
	{
		inst0 = methodDef.Body.Instructions[index - 3];
		inst1 = methodDef.Body.Instructions[index - 2];
		inst2 = methodDef.Body.Instructions[index - 1];
		inst3 = methodDef.Body.Instructions[index];

		//Check if we are using reflection to make a dynamic binding -
		if (inst0.ToString().Contains("ldstr") && inst1.ToString().Contains("ldnull") &&
			inst2.ToString().Contains("ldtoken") && inst3.ToString().Contains("GetTypeFromHandle"))
		{
			//var fullName = inst2.Operand.ToString() + inst0.Operand.ToString();
			var dyn = new MethodRef
			{
				Name = inst0.Operand.ToString(),
				ClassFullName = inst2.Operand.ToString(),
			};
			lock(_lock) dynBindings.Add(dyn);
		}


		//Check if we are using reflection to make a dynamic binding
		if (inst0.ToString().Contains("ldstr") && inst1.ToString().Contains("ldc.i4.1") &&
			inst2.ToString().Contains("newarr") && inst2.ToString().Contains("newarr System.Type") &&
			inst3.ToString().Contains("dup"))
		{
			//var fullName = inst2.Operand.ToString() + inst0.Operand.ToString();
			var dyn = new MethodRef
			{
				Name = inst0.Operand.ToString(),
				ClassFullName = inst2.Operand.ToString(),
			};
			lock(_lock) dynBindings.Add(dyn);
		}
	}
}`

here is my code which extracts a list of databinding elements from BAML

`        public List<IBaseRef> Analyze(ModuleDefMD module, string CurrentBAMLName, byte[] data)
        {
            var dynBindings = new List<IBaseRef>();
            Debug.Assert(BitConverter.ToInt32(data, 0) == data.Length - 4);

            BamlDocument document = BamlReader.ReadDocument(new MemoryStream(data, 4, data.Length - 4));

            foreach (BamlRecord item in document)
            {
                var txt = item as StringInfoRecord;
                if (txt != null)
                {
                    dynBindings.Add(new GlobalRef{Name = txt.Value} );
                    continue;
                }

                var txt2 = item as TextRecord;
                if (txt2 != null)
                {
                    dynBindings.Add(new GlobalRef { Name = txt2.Value });
                    dynBindings.Add(new GlobalRef { Name = txt2.Value.Replace("Command", "") });
                    continue;
                }

                var txt3 = item as PropertyWithConverterRecord;
                if (txt3 != null)
                {
                    dynBindings.Add(new GlobalRef { Name = txt3.Value });
                    continue;
                }

            }
            return dynBindings;
        }
@rollsch rollsch changed the title Databinding to public members with forceren enabled Databinding to public members with forceren enabled - Allow renaming of XAML/BAML references Jun 3, 2019
@XenocodeRCE XenocodeRCE added bug Something isn't working enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed labels Jun 3, 2019
@XenocodeRCE
Copy link
Owner

Hello,
nice find, thank you for the code. I think from here you can make a PR.
ConfuserEx WPF analyzer is pretty self explanatory, however if you got stuck just let me know :))

@rollsch
Copy link
Author

rollsch commented Jun 4, 2019

Can you give some pointers of where the analysers should be put?

Basically the process is as follows:
Analyse all WPF to build a list of databindings - Analyser1
Analyse all C# to build a list of dynamic bindings (eg using TypeOf and things like that) - Analyser2

Remove all items found in analyser1,analyser2 from the renaming (can I simply do this from within the analyser itself?)

Where would I inject these new analysers?

If I wanted to go a step further and rename within the BAML and C#, how would this work? The analyser isn't allowed to modify anything yet so it would need to store the results and then intercept during the rewrite process?

Can you explain the class layout to assist? Writing the code is easy but understanding the code structure is where I am falling over. I just hacked everything in to make it work as I couldn't figure out where to put the analysers or the program flow.

@XenocodeRCE
Copy link
Owner

right there :
https://github.com/XenocodeRCE/neo-ConfuserEx/tree/master/Confuser.Renamer/BAML
https://github.com/XenocodeRCE/neo-ConfuserEx/tree/master/Confuser.Renamer/Analyzers

basically debug the project while obfuscating your app, and keep your eyes on the variable values.
When it is about to make a mistake, just fix the code. I'm sure it's the matter of less then 2 lines of code.

@rollsch
Copy link
Author

rollsch commented Jun 4, 2019

So you are happy for me to modify the existing analysers and not make new ones?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants