Как взломать WinDbg анонимным методом?
-
19-09-2019 - |
Вопрос
Название в некотором роде говорит само за себя.Обычная команда SOS !бпмд без имени от этого мало толку.
Некоторые идеи, которые у меня были:
- сбросьте все методы, затем используйте !bpmd -md когда вы найдете соответствующий методdesc
- насколько я могу судить, непрактично в реальном использовании.Даже если бы я написал макрос, чтобы ограничить дамп анонимными типами / методами, нет очевидного способа отличить их друг от друга.
- используйте Reflector для вывода имени MSIL
- не помогает при работе с динамическими сборками и / или Reflection.Emit.Неспособность Visual Studio читать локальные переменные внутри таких сценариев - вот главная причина, по которой я в первую очередь обратился к Windbg...
- установите точку останова в VS, дождитесь ее достижения, затем перейдите на Windbg, используя неинвазивный трюк
- попытка отсоединиться от VS приводит к зависанию (вместе с приложением).Я думаю, это связано с тем, что управляемый отладчик является "мягкий" отладчик с помощью внедрения потока вместо стандартного "жесткого" отладчика.Или, может быть, это просто ошибка VS, специфичная для Silverlight (вряд ли будет первой Я сталкивался).
- установите точку останова в каком-либо другом месте, известном для вызова анонимного метода, затем выполните один шаг в
- мой запасной план, хотя я бы предпочел не прибегать к нему, если эти вопросы и ответы покажут лучший способ
Решение
Анонимный метод на самом деле не является анонимным.Он просто прячется за именем, сгенерированным компилятором.
Рассмотрим этот небольшой пример:
Func<int, int> a = (x) => x + 1;
Console.WriteLine(a.Invoke(1));
Чтобы найти возвращаемое значение, нам нужно найти название реализации метода.Чтобы сделать это, нам нужно найти MethodDesc окружающего метода.В этом примере это Main()
, так что:
0:000> !name2ee * TestBench.Program.Main
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00162c5c (TestBench.exe)
Token: 0x06000001
MethodDesc: 00163010
Name: TestBench.Program.Main()
JITTED Code Address: 001e0070
С помощью MethodDesc мы можем сбросить IL для Main()
0:000> !dumpil 00163010
ilAddr = 003f2068
IL_0000: nop
IL_0001: ldstr "press enter"
IL_0006: call System.Console::WriteLine
IL_000b: nop
IL_000c: call System.Console::ReadLine
IL_0011: pop
IL_0012: ldsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_0017: brtrue.s IL_002c
IL_0019: ldnull
IL_001a: ldftn TestBench.Program::<Main>b__0
IL_0020: newobj class [System.Core]System.Func`2<int32,int32>::.ctor
IL_0025: stsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_002a: br.s IL_002c
IL_002c: ldsfld TestBench.Program::CS$<>9__CachedAnonymousMethodDelegate1
IL_0031: stloc.0
IL_0032: ldloc.0
IL_0033: ldc.i4.1
IL_0034: callvirt class [System.Core]System.Func`2<int32,int32>::Invoke
IL_0039: call System.Console::WriteLine
IL_003e: nop
IL_003f: ret
Обратите внимание на забавно выглядящие названия.Это имена типа генерируемого делегата и фактического метода.Этот метод вызывается <Main>b__0
.Давайте рассмотрим этот метод:
0:000> !name2ee * TestBench.Program.<Main>b__0
Module: 6db11000 (mscorlib.dll)
--------------------------------------
Module: 00152c5c (TestBench.exe)
Token: 0x06000003
MethodDesc: 00153024
Name: TestBench.Program.<Main>b__0(Int32)
Not JITTED yet. Use !bpmd -md 00153024 to break on run.
Вот оно, у вас есть.MethodDesc равен 00153024, и, как говорится в комментарии, вы можете использовать !bpmd для установки точки останова с помощью MethodDesc .
Другие советы
Если найти "<>...." название сложное для вашего сценария, как насчет того, чтобы сделать его обычным методом?Обычно это очень просто;единственная сложная вещь - это захваченные переменные, но это не так уж плохо - например, они делают то же самое:
static void Main()
{
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
int div = 2;
foreach (var item in list.Where(x => x % div == 0))
{
Console.WriteLine(item);
}
ListSearcher ls = new ListSearcher();
ls.div = 2;
foreach (var item in list.Where(ls.Test))
{
Console.WriteLine(item);
}
}
class ListSearcher
{
public int div;
public bool Test(int x)
{
return x % div == 0;
}
}
Сбросьте дескриптор метода, на который указывает действие.Указания здесь.