Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Глубокие раскопки 1С (число прочтений - 1979 )
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Глубокие раскопки 1С
22. Ноября 2015 :: 04:44
Печать  
Надо было тут реализовать несколько сильно специфических штук, для чего пришлось сильно глубоко копнуть 1С. В некоторых местах аж до самого основания. Обнаружилось много интересного. Попишу пока сюда, может кому пригодится.
  
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Глубокие раскопки 1С
Ответ #1 - 22. Ноября 2015 :: 04:48
Печать  
Во-первых, пока не забыл, небольшая ошибка в заголовках:

Файл bkend.h

НЕ ПРАВИЛЬНО:
Код
Выбрать все
class IMPORT_1C CMetaDataObj
{
public:
	long m_ID; // ИД метаданного
	char * m_Code; // Вид метаданного, например, вид документа или справочника
	char * m_Present;
	char * m_Descr;
	... 



ПРАВИЛЬНО ТАК:
Код
Выбрать все
class IMPORT_1C CMetaDataObj
{
public:
	long m_ID; // ИД метаданного
	char * m_Code; // Вид метаданного, например, вид документа или справочника
	char * m_Descr;
	char * m_Present;
	... 


  
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Глубокие раскопки 1С
Ответ #2 - 22. Ноября 2015 :: 04:54
Печать  
Кстати есть некоторые более глубоко раскопанные структуры типа CSbCntSet, CStoreObj_Ref, CSubcContext, CExecutedModule, CExecutedModule, CCompiler и т.д. Оформлены в виде заголовочного файла для импорта в IDA. Расписаны таблицы виртуальных методов для основных классов, что сильно облегчает анализ кода в декомпиляторе. Если заинтересует, могу выложить текущую версию.
« Последняя редакция: 22. Ноября 2015 :: 13:46 - dfuy »  
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Глубокие раскопки 1С
Ответ #3 - 22. Ноября 2015 :: 05:00
Печать  
Ещё вот копал и по пути заметил такую вот вещь. Обнаружена функция GetMDDefFromValue. Суть функции на псевдокоде:
Код
Выбрать все
class CMetadataContext: public CBLContext
{
public:
	CMetaDataObj *m_Object;
	...
};

CMetaDataObj *__cdecl GetMDDefFromValue(CValue *Value)
{
  CBLContext *Context; // ecx@3

  if (Value
    && Value->Type.m_typecode == 100
    && (Context = Value->m_Context) != 0
    && Context->IsKindOf(RUNTIME_CLASS(CMetadataContext))
    return ((CMetadataContext*)Context)->m_Object;

  return 0;
} 



В связи с этим предлагается следующее изменение:

Файл MetaDataWork.cpp

Код
Выбрать все
case methGetMetaDataID:
{
	pBLContext		= ppValue[0]->GetContext();
	if (pBLContext == NULL)
		CBLModule::RaiseExtRuntimeError("В метод необходимо передавать объекты типа метаданных", 0);

	CString strClassName(pBLContext->GetRuntimeClass()->m_lpszClassName);
	if (strClassName != "CMetadataContext")
		CBLModule::RaiseExtRuntimeError("В метод необходимо передавать объекты типа метаданных", 0);

	CValue IsSelected;
	if( nmethIsSelected == 0 ) nmethIsSelected = pBLContext->FindMethod("Selected");
	pBLContext->CallAsFunc(nmethIsSelected, IsSelected, NULL);
	if( IsSelected.GetNumeric() == 0L )
		RuntimeError("В метод необходимо передавать непустые объекты типа метаданных");

	rValue = ((CMetaDataObj**)(long(pBLContext)+0x20))[0]->GetID();
} 



Правильно будет примерно так:

Код
Выбрать все
case methGetMetaDataID:
{
	CMetaDataObj *MDDef = ::GetMDDefFromValue(ppValue[0]);
	if (MDDef == NULL)
		CBLModule::RaiseExtRuntimeError("В метод необходимо передавать объекты типа метаданных", 0);

	rValue = MDDef->GetID();
} 



Может где ещё такой код есть, тогда аналогично.
  
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Недокументированные возможности функции EvalExpr
Ответ #4 - 22. Ноября 2015 :: 05:18
Печать  
Интереснейшая (для меня, по крайней мере) находка!
Наверное многие знакомы с полезной функцией
Код
Выбрать все
CBLModule::EvalExpr(char const *,CValue &,CValue **) 

Вычисляющей значения выражений, заданных текстовой строкой, причём в окружении текущего исполняемого кода с доступом даже ко всем локальным переменным. Вызывается которая обычно так:
Код
Выбрать все
CBLModule::GetExecutedModule()->EvalExpr(...) 


Заинтересовал меня её последний параметр (массив значений CValue**). В вызовах везде туда NULL передаётся.
Возникли у меня сразу подозрения, что туда можно передавать массив параметров, которые можно как-то использовать потом внутри выражения.
А я как раз такую штуку ну ООЧЕНЬ хотел, думал уже всякие извращённые методы применять. А тут обратил внимание и решил копнуть. Копать пришлось глубоко, но таки нашёл.

Гипотеза оказалась верна и результат таков: туда действительно передаётся массив параметров, а для доступа к ним в выражении нужно использовать конструкции вида %%N.
N - число, номер параметра в массиве (нумерация от 1).
Если использовать %%0, сработает как %%1. А если выйти за правую границу массива, 1С, естественно, упадёт, ибо размер массива сообщить некуда.
Если не передавать массив параметров (передать NULL), то такие конструкции будут считаться ошибкой синтаксиса.

Пользуйтесь на здоровье. Подмигивание
  
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Глубокие раскопки 1С
Ответ #5 - 22. Ноября 2015 :: 13:42
Печать  
По просьбам трудящихся текущая версия файла для IDA. Импортировать по Ctrl-F9. Виртуальные таблицы пока ещё далеко не все, лень пока ими заниматься. Только основные сделал для упрощения жизни и отработки технологии.

Технология позволяет видеть виртуальные вызовы в форме this->m_Context->vtable->GetCode(this->m_Context), что гораздо лучше того мусора, который генерируется изначально, да и позволяет декомпилятору правильно оценить формат вызываемой функции, без чего он опухает анализировать стек.

Кстати, иногда часть этого мусора всё же остаётся, и вызов выглядит примерно так: ((int (*)(void))Context->vtable->GetNProps)(). В таком случае надо жать на методе правую кнопку мыши и выбирать "Force call type".
  

1c_classes.7z ( 8 KB | Загрузки )
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Глубокие раскопки 1С
Ответ #6 - 22. Ноября 2015 :: 13:43
Печать  
А ещё сгенерировал файлик для строковых ресурсов, ибо тоже гемор каждые 5 сек лазить искать эти идентификаторы там. Работает просто: также его надо импортировать по Ctrl-F9, там внутри гигантский enum. Потом в IDA на идентификаторе нажимаем M, выбираем значение из этого enum'a и по названию понимаем, что за ним скрывается.
  

1c_strres.7z ( 110 KB | Загрузки )
Наверх
 
IP записан
 
dfuy
Junior Member
**
Отсутствует



Сообщений: 41
Зарегистрирован: 18. Марта 2013
Re: Глубокие раскопки 1С
Ответ #7 - 22. Ноября 2015 :: 13:50
Печать  
Наиболее свежую версию IDA из серии 6.6 можно взять тут: https://yadi.sk/d/GjJCkDxQdyPGk (ссылка из темы https://forum.reverse4you.org/showthread.php?t=1931)

Эх, научиться бы ещё к ней плагины писать, горы можно было бы свернуть!
  
Наверх
 
IP записан
 
MadDAD
Junior Member
**
Отсутствует


1C++ rocks!

Сообщений: 22
Зарегистрирован: 17. Ноября 2015
Re: Глубокие раскопки 1С
Ответ #8 - 17. Августа 2016 :: 13:42
Печать  
dfuy писал(а) 22. Ноября 2015 :: 13:42:
По просьбам трудящихся текущая версия файла для IDA. Импортировать по Ctrl-F9.


Спасибо огромное за труд, очень пригодилось.

Мне не хватило описания CTypedValue.  Добавил его, прикрепляю обновленную версию.

Не прикрепляю, опять беда с вложениями. Не нашел где кнопка Печаль
Вот ссылка на cloud.mail.ru : https://cloud.mail.ru/public/8MCv/H24MLteKK
  
Наверх
 
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать