使用Obfuscation进行Proto-buf序列化

时间:2011-11-29 02:11:20

标签: serialization obfuscation protobuf-net

我正在寻找关于使用带混淆的原型buf网(Dotfuscator)时发生了什么的一些指导。项目的一半是DLL,另一半是其他地方的EXE,使用proto-buf NET,它们可以完美地交换数据。直到我混淆DLL。

此时P-BN失败而没有引发异常,不同地返回一个0长度的字节数组或一个缩短的字节数,这取决于我摆弄的内容。这个类很简单(VB):

<ProtoContract(Name:="DMailer")> _
Friend Class DMailer

    Private _Lic As Cert
    Private _Sys As Sys
    Private _LList As List(Of LItem)

    ..
    ..
End Class

有3个道具全部用ProtoMember装饰来获取/设置组成类对象。为了简洁起见。

同样,它在我混淆DLL之前一直很好用。然后,Dotfuscator将这些中的每一个重命名为null,显然因为他们都是朋友,这似乎扼杀了proto-buff。如果我免除该类重命名(只是类名,而不是道具/成员),它似乎再次起作用。有意义的是,P-BN只能对具有正确名称的对象进行操作,但是当被要求序列化一个空命名对象时,似乎异常可能是有序的。

另一方面,PB-N的许多魅力应该是从属性开始的.NET名称的序列化独立 - 至少我理解它。但在这种情况下,它似乎只适用于具有名称的类。我尝试使用如上所示的Name限定符或参数,但无济于事 - 它显然没有按照我的想法行事。

所以,我很好奇,如果:

a)......我基本上已经正确地推测了这个问题

b)...还有一些其他属性或标志可能有助于序列化 null命名对象

c)...如果有任何其他见解可以提供帮助。

如果我免除所有3或4个类的Dotfuscator重命名(LList尚未实现,离开DMailer,Cert和Sys),DLL似乎再次起作用 - 至少输出的大小正确。我可以忍受这一点,虽然模糊的名字会更好:Dotfuscator(CE)要么免除它们,要么将名称设置为Null - 我似乎找不到强制重命名的方法。

我考虑的一种替代方法是将Cert和Sys的Serializer输出存储为DMailer中的字节数组或Base64字符串而不是类,而不是免除3或4个类的重命名。然后让接收器单独反序列化每个对象。能够解开一件东西并将你的玩具放在那里就像魔法一样,真是太好了。

(许多)TIA

2 个答案:

答案 0 :(得分:4)

有趣。我承认我从未尝试过这种情况,但是如果你可以引导我完成你的过程(或者更好:也许提供一个基本的复制示例“运行这个,然后这个,那么:繁荣”)我很乐意调查。

注意:ProtoContract上的Name主要用于GetProto()用途;核心序列化器不需要它,可以省略以减少您的曝光。此外,protobuf-net对字段不感兴趣,除非这些字段使用属性进行修饰,因此这不应成为问题。

然而!这里可能有一个解决方法, now ;你可以预先生成一个静态序列化dll;例如在一个单独的控制台exe中(就像一个工具;我真的需要将它包装在一个独立的实用程序中!)

因此,如果您创建一个引用未经模糊处理的库和protobuf-net.dll的控制台exe:

var model = RuntimeTypeModel.Create();
model.Add(typeof(DMailer), true); // true means "use the attributes etc"
// and other types needed, etc
model.Compile("MailSerializer", "MailSerializer.dll");

这应该写MailSerializer.dll,然后您可以从代码(除protobuf-net之外)引用,并使用:

var ser = new MailSerializer(); // our pre-genereated serializer
ser.Serialize(...); // etc

然后在您的混淆有效负载中包含MailSerializer.dll

(这是所有v2特定的,顺便说一下)

如果没有工作,我需要调查主要问题,但我不是混淆专家,所以可以用你的重复步骤。

答案 1 :(得分:2)

由于有一些兴趣上升,这看起来会起作用:

a)任何形式的反射都不能获得混淆类型的属性列表。 我尝试通过所有类型来寻找带有ProtoContract的类型,我可以找到它们 但属性名称全部更改为a,m,b,j,g。

我也尝试了Me.GetType.GetProperties,结果相同。

可以从输出中实现一个映射,以指示Employee.FirstName现在是a0.j,但是分发它会破坏混淆的目的。

b)在某种程度上工作的是免除NAME类的混淆。由于PB-N查找ProtoMember属性以获取数据,因此您可以对属性/成员名称进行模糊处理,而不是CLASS /类型名称。如果名称类似于FederalReserveLogIn,那么您的类/类型就有一个靶心。

我在以下方面取得了初步成功:

1)构建一个简单的类来存储属性令牌和值。使用ConvertFromInvariantString将所有内容存储为字符串。从PBN获取提示,我使用了一个整数作为令牌:

<ProtoMember(propIndex.Foo)>
Property Foo As String

枚举有助于以后将所有内容组合在一起。将它们存储在Dictionary(Of T, NameValuePair)

2)添加一些访问者。这些可以为您执行类型转换:

  Public Sub Add(ByVal Key As T, ByVal value As Object)
        If _col.ContainsKey(Key) Then
            _col.Remove(Key)
        End If

        _col.Add(Key, New TValue(value))

    End Sub

    Public Function GetTItem(Of TT)(key As T) As TT
        If _col.ContainsKey(key) Then
            Return CType(_col(key).TValue, TT)
        Else
            Return Nothing
        End If
    End Function

T是您希望使用的任何密钥类型。整数产生最小的输出,仍然允许订阅代码使用枚举。但它可能是String。

TT是原始类型:

myFoo = props.GetTItem(Of Long)(propsEnum.Foo)

3)将内部列表(字典)暴露给PBN和宾果游戏,全部完成。

它也非常容易为点,矩形,字体,大小,颜色甚至位图添加转换器。

HTH