Конференция ".Net" » Раздолье для крякеров?
 
  • DiamondShark © (07.08.05 22:31) [0]
    Пишем класс:


    public class TestClass
    {
    private int FValue;
    public TestClass(int val) : base()
    {
     FValue = val;
    }

    public int Value
    {
     get { return FValue; }

    }
    }



    Простенькое тестовое приложение:


    static void Main(string[] args)
    {
    TestClass tc = new TestClass(123);

    Type t = tc.GetType();
    FieldInfo[] fields = t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
    foreach (FieldInfo field in fields) Console.WriteLine(field.Name);
    }




    Замечательно. В списке видим поле FValue.
    Ещё один тест:

    static void Main(string[] args)
    {
    TestClass tc = new TestClass(123);
    Console.WriteLine(tc.Value);
    Type t = tc.GetType();
    t.InvokeMember("FValue", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField , null, tc, new object[]{456}
    );
    Console.WriteLine(tc.Value);  
    }


    В консоли видим:
    123
    456
    Приватное поле без проблем поменяли!

    Не, я понимаю, что такая навороченная система метаинформации -- это мощь и крутота.
    Ну в чём тогда смысл разграничений private, public? Срам фигой прикрывать?
  • Lamer@fools.ua © (08.08.05 08:43) [1]
    Думаю, пришлось сделать такую "дыру" для возможности сериализации, а особенно десериализации объектов.
  • Lamer@fools.ua © (08.08.05 08:44) [2]
    P.S. к [1].
    Я имею в виду автоматические сериализацию и десериализацию с помощью атрибута SerializableAttribute.
  • Ломброзо © (13.08.05 00:51) [3]
    Сильно подозреваю, что и сей класс, и сей тест-юнит - в одной сборке, посему хак и удался. Подозреваю, что ежели разнести их в разные сборки - нихрена не выйдет.
  • Lamer@fools.ua © (13.08.05 09:14) [4]
    >>Ломброзо ©   (13.08.05 00:51) [3]

    >Сильно подозреваю, что и сей класс, и сей тест-юнит - в одной сборке, посему хак и удался. Подозреваю, что ежели разнести их в разные сборки - нихрена не выйдет.

    Подозрения неверны. Выйдет.
  • oslep (14.08.05 11:05) [5]
    Вот один пример. Решил я вчера попробовать создать потомка TreeView. Ну думаю, щас оконную процедуру поменяю и все хорошо. А где брать WM_, TVM_ etc.? Директива uses Windows автоматически включает сборки Borland в мою сборку, чего не очень-то хотелось. После копания по иерархии FCL оказалось, что все эти константы имеются в составе System.Windows.Forms в защищенном (или даже приватном) классе NativeMethods. В защищенном - это значит, что разработчики, стремясь к платформо-независимости, не желают открывать публичный доступ для внутренней реализации их классов. Но сделать это можно. Я поступил так:


    interface

    uses
     System.Reflection;

    type

     PropertyAdapter = class
     protected
       procedure CloneProperties(SourceAssemblyName, SourceTypeName: System.string); virtual;
       constructor Create(SourceAssemblyName, SourceTypeName: System.string); virtual;
     end;

     NativeMethodsAdapter = class(PropertyAdapter)
     private
     protected
     public
       fWM_CREATE: Integer;
       fWM_MOVE, fWM_MOVING: Integer;
       constructor Create; reintroduce; virtual;
       property WM_MOVE: Integer read fWM_MOVE;
       property WM_MOVING: Integer read fWM_MOVING;
       property WM_CREATE: Integer read fWM_CREATE;
     end;

    function GetCurrentAppDomainAssembly(AssemblyName: System.string): Assembly;

    function GetCurrentAppDomainAssemblyObject(SourceAssemblyName, SourceTypeName: System.string): System.object;

    implementation

    function GetCurrentAppDomainAssembly(AssemblyName: System.string): Assembly;
    var
     Assemblies        : array of Assembly;
     I                 : Integer;
    begin
     Result := Assembly.LoadWithPartialName(AssemblyName);
     if Assigned(Result) then
       Exit
     else
     begin
       Assemblies := AppDomain.get_CurrentDomain.GetAssemblies;
       for I := Low(Assemblies) to High(Assemblies) do
       begin
         Result := Assemblies[I];
         if Result.GetName.Name.Equals(AssemblyName) then
           Exit
         else
           Result := nil;
       end;
     end;
    end;

    function GetCurrentAppDomainAssemblyObject(SourceAssemblyName, SourceTypeName: System.string): System.object;
    var
     SourceAssembly    : Assembly;
     SourceType        : System.Type;
    begin
     Result := nil;
     SourceAssembly := GetCurrentAppDomainAssembly(SourceAssemblyName);
     if Assigned(SourceAssembly) then
       with SourceAssembly do
       begin
         SourceType := GetType(System.string.Format('{0}.{1}', [SourceAssemblyName, SourceTypeName]));
         if Assigned(SourceType) then
           Result := Activator.CreateInstance(SourceType);
       end;
    end;

    { PropertyAdapter }

    procedure PropertyAdapter.CloneProperties(SourceAssemblyName, SourceTypeName: System.string);
    var
     MyProps           : array of PropertyInfo;
     MyProp            : PropertyInfo;
     MyField           : FieldInfo;
     SourceObject      : System.object;
     SourceField       : FieldInfo;
    begin
     SourceObject := GetCurrentAppDomainAssemblyObject(SourceAssemblyName, SourceTypeName);
     if Assigned(SourceObject) then
     begin
       MyProps := GetType.GetProperties;
       if Assigned(MyProps) then
         for MyProp in MyProps do
         begin
           SourceField := SourceObject.GetType.GetField(MyProp.Name);
           if Assigned(SourceField) then
           begin
             MyField := GetType.GetField('f' + MyProp.Name);
             MyField.SetValue(Self, SourceField.GetValue(SourceObject));
           end;
         end;
     end;
    end;

    constructor PropertyAdapter.Create(SourceAssemblyName, SourceTypeName: System.string);
    begin
     inherited Create;
     CloneProperties(SourceAssemblyName, SourceTypeName);
    end;

    { NativeMethodsAdapter }

    constructor NativeMethodsAdapter.Create;
    begin
     inherited Create('System.Windows.Forms', 'NativeMethods');
    end;

    end.



    Как видно из кода, определяя свойства только для чтения с внутренними полями (NativeMethodsAdapter.WM_CREATE read fWM_CREATE) при создании экземпляра можно инициализировать эти поля свойствами защищенного в сборке System.Windows.Forms объекта. Вариант, разумеется не конечный, только тест, но Ваши мнения будут полезны всем нам. Думаю, таким же образом можно создавать и реализацию методов.

    С другой стороны, взглянув на любую сборку при помощи утилиты Reflector на http://www.aisto.com/roeder/dotnet, понимаешь, что секретов не то что-бы нет, но они как-то так... Короче, не знаю, возмущаться или нет. И с одной стороны, разделяю возмущение автора.
  • oslep (14.08.05 11:18) [6]
    Кстати, одно маленькое дополнение. Заметил, что поля fWM_MOVE и т.д. у меня public. Избавляемся от этого:

     NativeMethodsAdapter = class(PropertyAdapter)
     private
     protected    
       fWM_CREATE: Integer;
       fWM_MOVE, fWM_MOVING: Integer;
     public
       constructor Create; reintroduce; virtual;
       property WM_MOVE: Integer read fWM_MOVE;
       property WM_MOVING: Integer read fWM_MOVING;
       property WM_CREATE: Integer read fWM_CREATE;
     end;

    и далее, по тексту:

    procedure PropertyAdapter.CloneProperties(SourceAssemblyName, SourceTypeName: System.string);
    //.....
           if Assigned(SourceField) then
           begin
             MyField := GetType.GetField('f' + MyProp.Name, BindingFlags.NonPublic or BindingFlags.Instance);
             MyField.SetValue(Self, SourceField.GetValue(SourceObject));
           end;
    //.....
  • Lamer@fools.ua © (14.08.05 23:26) [7]
    Вот, что нашёл в MSDN (index: "security, reflection"):

    Providing access to nonpublic information involves security risks. Code that is allowed to discover nonpublic information on a type can potentially access code, data, and other information you want to keep private. Therefore, .NET Framework security enforces rules that determine to what degree reflection can be used to discover type information and access types. Depending on the operation being performed, a ReflectionPermission or the SecurityPermission for serialization might be required.

    ...
  • jack128 © (25.10.05 12:58) [8]
    Мда. Вобщем то доступ к закрытым полям и в дельфи(обычной, по крайней мере в семерке) можно получить.

    procedure TObject.CleanupInstance;
    {$IFDEF PUREPASCAL}
    var
     ClassPtr: TClass;
     InitTable: Pointer;
    begin
     ClassPtr := ClassType;
     InitTable := PPointer(Integer(ClassPtr) + vmtInitTable)^;
     while (ClassPtr <> nil) and (InitTable <> nil) do
     begin
       _FinalizeRecord(Self, InitTable); // вот оно. Ссылка на TypeInfo полей
       ClassPtr := ClassPtr.ClassParent;
       if ClassPtr <> nil then
         InitTable := PPointer(Integer(ClassPtr) + vmtInitTable)^;
     end;
    end;

  • jack128 © (25.10.05 12:59) [9]
    правда не по имени, но уже кое что :-)
  • Суслик © (25.10.05 16:30) [10]
    а можно fillchar(pointer(obj)^, ... сделать.
    тоже доступ к полям :)
  • ИА (25.10.05 18:34) [11]
    Это распространенное заблуждение - ограничение доступа к полям/методам объекта в ОО не средство обеспечить безопасность, а только реализация инкапсуляции/полиморфизма. К защите данных/методов не имеет отношения.
    Отмеченые выше типы permission (i.e. ReflectionPermission) не есть способ ограничить доступ к вашему коду, а способ отрезать такой доступ от конкретного чужого кода. Короче, думайте об этом как о простом сокрытии по принципу "меньше знаешь - легче спишь"
  • Polevi © (05.11.05 18:00) [12]
    >ИА   (25.10.05 18:34) [11]
    согласен полностью
 
Конференция ".Net" » Раздолье для крякеров?
Есть новые Нет новых   [134430   +3][b:0][p:0.003]