Skip to content

Instantly share code, notes, and snippets.

@ganwell
Created September 23, 2012 16:48
Show Gist options
  • Save ganwell/3772267 to your computer and use it in GitHub Desktop.
Save ganwell/3772267 to your computer and use it in GitHub Desktop.
Symbol renamer for .net / mono
/// I used Mono.Cecil 0.9.5
/// This code is proof of concept quality!
using System;
using Mono.Cecil;
using System.Collections.Generic;
using Mono.Cecil.Cil;
using System.IO;
using Mono.Collections.Generic;
namespace ch.fangorn.LUI.RenameSymbols
{
internal static class MyExtensions
{
public static void V (this string str)
{
if (MainClass.verbose)
Console.WriteLine (str);
}
public static void W (this string str)
{
Console.WriteLine ("Warn: " + str);
}
public static void C (this string str)
{
Console.WriteLine (str);
}
}
class MainClass
{
public static bool verbose = false;
public static void Main (string[] args)
{
if (args.Length < 3) {
Console.WriteLine ("renameSymbols input output libsDir [/v]");
Console.WriteLine (" /v verbose");
return;
}
string assemblyName = args [0];
string output = args [1];
string libs = args [2];
((DefaultAssemblyResolver)GlobalAssemblyResolver.Instance).AddSearchDirectory (libs);
if (args.Length > 3) {
verbose = args [3] == "/v";
}
ModuleDefinition module = ModuleDefinition.ReadModule (assemblyName);
SymbolRename sr = new SymbolRename (module);
foreach (TypeDefinition type in module.Types) {
if (type.FullName.StartsWith ("ch.fangorn.")) {
sr.Rename (type);
}
}
module.Write (output);
sr.WriteDecodeList (output + ".xdb");
}
}
internal class Symbol
{
public TokenType symbolType;
public string fullName;
public string name;
public Symbol (TokenType symbolType, string fullName, string name)
{
this.symbolType = symbolType;
this.fullName = fullName;
this.name = name;
}
public override int GetHashCode ()
{
return symbolType.GetHashCode () ^ fullName.GetHashCode ();
}
public override bool Equals (object obj)
{
Symbol other = obj as Symbol;
if (other == null)
return false;
if (fullName == null)
return false;
return symbolType.Equals (other.symbolType) && fullName.Equals (other.fullName);
}
}
internal class Children : Dictionary<TypeDefinition, Dictionary<TypeDefinition, bool>>
{
public void BuildChildren (TypeDefinition type)
{
foreach (TypeDefinition nested in type.NestedTypes)
BuildChildren (nested);
List<TypeDefinition> parentList = new List<TypeDefinition> ();
if (type.BaseType != null)
parentList.Add (type.BaseType.Resolve ());
foreach (TypeReference tref in type.Interfaces)
parentList.Add (tref.Resolve ());
foreach (TypeDefinition parent in parentList) {
Dictionary<TypeDefinition, bool> childrenList;
if (TryGetValue (parent, out childrenList) == false) {
childrenList = new Dictionary<TypeDefinition, bool> ();
Add (parent, childrenList);
}
childrenList [type] = true;
}
}
public List<MethodDefinition> GetVirtualChilds (MethodDefinition method)
{
List<MethodDefinition> childs = new List<MethodDefinition> ();
GetVirtualChilds (childs, method.DeclaringType.Resolve (), method.Name);
return childs;
}
private void GetVirtualChilds (List<MethodDefinition> childs, TypeDefinition type, string name)
{
Dictionary<TypeDefinition, bool> childrenList;
if (TryGetValue (type, out childrenList)) {
foreach (TypeDefinition child in childrenList.Keys) {
GetVirtualChilds (childs, child, name);
foreach (MethodDefinition method in child.Methods)
if (method.Name.Equals (name))
childs.Add (method);
}
}
}
public bool IsVirtualRoot (MethodDefinition method)
{
TypeDefinition parentType = null;
TypeReference pRef = method.DeclaringType.BaseType;
while (pRef != null) {
parentType = pRef.Resolve ();
if (parentType != null) {
foreach (MethodDefinition parentMethod in parentType.Methods) {
if (parentMethod.Name.Equals (method.Name)) {
return false;
}
}
}
pRef = parentType.BaseType;
}
foreach (TypeReference tinterface in method.DeclaringType.Interfaces) {
parentType = tinterface.Resolve ();
foreach (MethodDefinition parentMethod in parentType.Methods) {
if (parentMethod.Name.Equals (method.Name)) {
return false;
}
}
}
return true;
}
}
internal class SymbolRename
{
private int currentSymbolId = 0;
private Dictionary<Symbol, string> symbolMap = new Dictionary<Symbol, string> ();
private Children children = new Children ();
private ModuleDefinition module;
public SymbolRename (ModuleDefinition module)
{
this.module = module;
foreach (TypeDefinition type in this.module.Types)
children.BuildChildren (type);
}
public bool CheckNoRename (Collection<CustomAttribute> attrs)
{
foreach (CustomAttribute attr in attrs) {
if (attr.AttributeType.Name == "NoRenameAttribute")
return true;
}
return false;
}
public void Rename (TypeDefinition type)
{
if (CheckNoRename (type.CustomAttributes))
return;
if (type.IsRuntimeSpecialName)
return;
if (!type.IsPublic) {
if (type.Name == "<Module>")
return;
foreach (TypeDefinition nested in type.NestedTypes)
Rename (nested);
RenameAllMember (type, true);
if (type.Name == "Resources")
return;
AddMapping (type);
} else {
RenameAllMember (type);
}
}
private void RenameAllMember (TypeDefinition type)
{
RenameAllMember (type, false);
}
private void RenameAllMember (TypeDefinition type, bool viaPrivate)
{
foreach (MethodDefinition method in type.Methods)
Rename (method, viaPrivate);
foreach (PropertyDefinition property in type.Properties) {
Rename (property.SetMethod, viaPrivate);
Rename (property.GetMethod, viaPrivate);
}
foreach (FieldDefinition field in type.Fields) {
if (!field.IsPublic || viaPrivate) {
if (field.IsAssembly)
continue;
if (field.Name == "version")
continue;
if (field.Name == "collection")
continue;
if (field.Name == "next")
continue;
if (field.Name == "current")
continue;
if (field.Name == "container")
continue;
if (field.Name == "Array")
continue;
if (CheckNoRename (field.CustomAttributes))
continue;
AddMapping (field);
}
}
}
private void Rename (MethodDefinition method, bool viaPrivate)
{
if (method == null)
return;
if (CheckNoRename (method.CustomAttributes))
return;
if (method.IsRuntimeSpecialName)
return;
if (method.Name == "Invoke")
return;
if (method.Name == "BeginInvoke")
return;
if (method.Name == "EndInvoke")
return;
if (!method.IsPublic || viaPrivate) {
if (method.IsVirtual) {
if (children.IsVirtualRoot (method)) {
RenameVirtual (method);
}
} else if (!method.IsConstructor && !method.IsNative
&& !method.IsPInvokeImpl && !method.IsUnmanaged && !method.IsAssembly) {
if (method.Name == "GetEnumerator")
return;
AddMapping (method);
}
}
RenameParameters (method);
}
private void RenameVirtual (MethodDefinition method)
{
string newName = CreateMapping (method);
foreach (MethodDefinition subMethod in children.GetVirtualChilds(method))
subMethod.Name = newName;
method.Name = newName;
}
private void RenameParameters (MethodDefinition method)
{
foreach (ParameterDefinition param in method.Parameters) {
TokenType symbolType = param.MetadataToken.TokenType;
Symbol s = new Symbol (symbolType, method.FullName + ":" + param.Name, param.Name);
string newName;
if (symbolMap.TryGetValue (s, out newName)) {
("Existing rename " + symbolType.ToString () + ": " + s.fullName + "->" + newName).W ();
} else {
newName = "Xp" + currentSymbolId.ToString ("X5");
currentSymbolId++;
symbolMap.Add (s, newName);
("Rename " + symbolType.ToString () + ": " + s.fullName + "->" + newName).V ();
}
param.Name = newName;
}
}
private string CreateMapping (MemberReference tref)
{
TokenType symbolType = tref.MetadataToken.TokenType;
Symbol s = new Symbol (symbolType, tref.FullName, tref.Name);
string newName;
if (symbolMap.TryGetValue (s, out newName)) {
("Existing rename " + symbolType.ToString () + ": " + tref.FullName + "->" + newName).W ();
} else {
newName = "Xm" + currentSymbolId.ToString ("X5");
currentSymbolId++;
symbolMap.Add (s, newName);
("Rename " + symbolType.ToString () + ": " + tref.FullName + "->" + newName).V ();
}
return newName;
}
private void AddMapping (MemberReference tref)
{
tref.Name = CreateMapping (tref);
}
public void WriteDecodeList (string filename)
{
FileStream fs = File.OpenWrite (filename);
StreamWriter sw = new StreamWriter (fs);
foreach (Symbol s in symbolMap.Keys) {
sw.WriteLine (symbolMap [s] + "\0" + s.name);
}
sw.Close ();
}
}
}
#!/bin/sh
BUILDDIR=????
CONTENTSDIR=????
BUNDLE=????
mono ../Resources/ILRepack.exe /internalize "/lib:$BUNDLE" "/out:$BUNDLE/tmp.exe" "$BUNDLE/CardBoard.exe" "$BUNDLE/Access.dll" "$BUNDLE/CBLogic.dll" "$BUNDLE/CBProtocols.dll" "$BUNDLE/CBData.dll"
rm "$BUNDLE/CardBoard.exe" "$BUNDLE/Access.dll" "$BUNDLE/CBLogic.dll" "$BUNDLE/CBProtocols.dll" "$BUNDLE/CBData.dll"
mono ../Resources/renameSymbols.exe "$BUNDLE/tmp.exe" "$BUNDLE/CardBoard.exe" "$BUNDLE" /v
rm "$BUNDLE/tmp.exe"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment