Lotus Script: взгляд изнутри

Y

Yakov

Здравствуйте, уважаемые разработчики.

Краткая заметка о виртуальной машине LS и системе ее команд находится во вложении.
А здесь мы рассмотрим некоторые примеры.

Преобразования типов и встроенные функции
Встроенные функции, возвращающие строки, (Chr, Ucase, Lcase и другие) в зависимости от написания (Chr или Chr$) возвращают либо Variant of DataType 8 (String), либо String.
Посмотрим, как это выглядит "внутри".
Код:
Dim s As String
s = Chr(13)
s = Chr$(13)
После трансляции:
Код:
	Dim S As String
line # 
lvalue_l S
push_long 13
Chr
Cvar
Cstr
Let
line # 
lvalue_l S
push_long 13
Chr
Cstr
Let
В первом присвоении выполняется лишнее преобразование типов, чего можно избежать, используя "$" в имени функции.

Select Case
Код
Код:
Public Sub printNumber(x As Integer)
Select Case x
Case 0: Print "zero"
Case 1: Print "one"
Case Else: Print "something else"
End Select
End Sub
транслируется в
Код:
Public Sub PRINTNUMBER(X As Integer)
line # 13
line # 
goto label_3
label_0:
line # 14
stack_copy
push_int_0
=
if_false_goto label_1
pop
line # 
push_str_const {zero}
Print
line # 
goto label_4
label_1:
line # 15
stack_copy
push_int_1
=
if_false_goto label_2
pop
line # 
push_str_const {one}
Print
line # 
goto label_4
label_2:
pop
line # 16
push_str_const {something else}
Print
line # 
goto label_4
label_3:
line # 
rvalue_pi X
goto label_0
label_4:
line # 18
end_routine
End Sub
Что здесь происходит. Переменная x сравнивается с каждым из значений в операторе Select Case последовательно. Если есть совпадение, выполянется соответствующий код и происходит переход на следующую за End Select строчку. Таким образом, если в вашем коде одна из веток Case ... встречается чаще других, ее следует поставить на первое место.

Вычисление булевых значений (операторы And, Or)
Некоторые компиляторы языков высокого уровня допускают частичное вычисление булевых значений: вычисление прекращается, как только будет известно его значение. К примеру, значение выражения False And x = 0 известро еще до вычисления значения x = 0, оно равно False. Компилятор языка Lotus Script всегда выполняет полное вычисление булевых значений, поэтому в LS невозможна проверка вида
Код:
If Not document Is Nothing And document.Created > cutOff Then
...
End If
Код:
	rvalue_p DOCUMENT
push_Nothing
Is
Not
rvalue_object DOCUMENT
push_property CREATED
call_routine
rvalue_p CUTOFF
>=
And
if_false_goto label_0
...
label_0:
Если все таки document Is Nothing, то вычисление document.Created вызовет ошибку.

Переменного числа аргументов не существует
Компилятор подставляет пропущенные значения.
Код:
Print Instr(x, "a")
транслируется в
Код:
	push_1
rvalue_l X
push_str_const {b}
push_int 0
Instr
Print
Код:
Dim uiWorkspace As New NotesUIWorkspace()
Call uiWorkspace.Prompt(PROMPT_OK, "Test", "OK")
транслируется в
Код:
line # 
lvalue_l UIWORKSPACE
push_constructor NOTESUIWORKSPACE
сall_constructor
Set
line # 
rvalue_object UIWORKSPACE
push_routine PROMPT
push_num_const PROMPT_OK = 1
push_str_const {Test}
push_str_const {OK}
push_int 0
push_int 0
call_routine
pop

Расширенный синтаксис
Пришло время поставить все точки над ё в вопросе о расширенном синтаксисе. Сравним:
Код:
	Print document.GetItemValue("Form")(0)
Print document.Form(0)

Call document.ReplaceItemValue("Form", "test")
document.Form = "test"
и
Код:
line # 
rvalue_object DOCUMENT
push_lsx_routine GETITEMVALUE
push_str_const {Form}
call_routine
push_int_0
rvalue_arr
Print

line # 
rvalue_object DOCUMENT
push_notes_function FORM
push_int_0
call_notes_function
Print

line # 
rvalue_object DOCUMENT
push_lsx_routine REPLACEITEMVALUE
push_str_const {Form}
push_str_const {test}
call_routine
pop

line # 
rvalue_object DOCUMENT
lvalue_document_field FORM
push_str_const {test}
Let


А теперь переходим к части, обозначенной подзаголовком. Ваши вопросы, господа и дамы.
 

Вложения

  • ls_uncovered.txt
    14,4 КБ · Просмотры: 657

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
так а чего коментов по расширенному синтаксису нету? ;)

и почему не указано чем производилось дизассемблирование?
я вот сейчас как раз пишу анализатор LS - выложу потому всем кому интересно будет
поэтому мне было бы более интересно если бы статья приобрела более расширенный вид
 
A

Akupaka

Пришло время поставить все точки над ё в вопросе о расширенном синтаксисе.
так, а как на счет точек-то? )
мы видим лишь, что выполняются разные макросы, но это ни на что не указывает ;)
фактически, мы не знаем, что происходит на самом деле...

или я чего-то не понял? :)
 
Y

Yakov

ToxaRat, дизассемблирование производилось "в уме". ;) То есть самописной тулзой. Какое расширение статьи вы хотите увидеть? Задавайте вопросы, я постараюсь на них ответить.
Akupaka, мы видим, что выполняемый код - разный. И можно лишь говорить о том, что компилируется эквивалентный код в смысле получаемых результатов, но не одинаковый.
Рассмотрим подробнее, что делает ВМ в обоих случаях. Хочу сразу предупредить, что как она это делает, я не знаю.
Call document.ReplaceItemValue("Form", "test")
В этом случае ВМ
Код:
	rvalue_object DOCUMENT ;кладет на стек данных объект DOCUMENT
push_lsx_routine REPLACEITEMVALUE ;кладет на стек вызовов адрес функции NotesDocument.ReplaceItemValue; класс и его функция находятся в библиотеке nlsxbe.dll
push_str_const {Form} ;кладет на стек данных строковую константу
push_str_const {test} ;кладет на стек данных строковую константу
call_routine ;вызывает функцию с вершины стека вызовов
pop ;выталкивает со стека данных неиспользуемый результат функции
Случай document.Form = "test":
Код:
	rvalue_object DOCUMENT ;кладет на стек объект DOCUMENT
lvalue_document_field FORM ;кладет на стек адрес поля FORM
push_str_const {test} ;кладет на стек строковую константу
Let ;осуществляет присвоение значения переменной
ВМ в разных случаях выполняет разные инструкции. Возможно, в итоге будет выполнена одна и та же последовательность вызовов функций Lotus API.
Хочу также отметить, что я не являюсь противником расширенного синтаксиса, я лишь хочу показать, что это не одно и то же, а две большие разницы.
Анонс. Через некоторое время (~полгода :-D) я покажу еще одно преимущество GetItemValue/ReplaceItemValue перед расширенным синтаксисом.
 
A

Akupaka

можешь сказать, что вернет?
set notesItem = document.ReplaceItemValue("Form", "test")

самое интересно, что я противник расширенного синтаксиса ))
"это не одно и то же, а две большие разницы" почему это? результат один, потому я и указал, что мы видим две последовательности макросов, но т.к. мы не знаем, что делают эти макросы на более низком уровне, то мы не можем быть уверенными, что это разные вещи :) (не для спора, просто имхо)
кстати, не планируешь выложить какую-то тулзу, которая позволила бы эксперементировать с дизассемблированием? ;)
 
O

Omh

Akupaka, так выкладывал же...
Которая приводила дамп к читабельному виду.

Я так понимаю, она парсила именно это:
Код:
Секция определений содержит описания всех используемых в библиотеке элементов
 
A

Akupaka

та утилита делала то же самое, что тут в теме? я ж ее не смотрел ;)
 
Y

Yakov

Akupaka
Код:
Public Sub TEST(DOCUMENT As NOTESDOCUMENT)
Dim ITEM As NOTESITEM
line # 13
lvalue_l ITEM
rvalue_object DOCUMENT
push_lsx_routine REPLACEITEMVALUE
push_str_const {Form}
push_str_const {test}
call_routine
Set
line # 14
end_routine
End Sub
Тулзу выкладывать не собираюсь, потому что есть еше люди, которые пишут коммерческий код на LS и считающие его недекомпилируемым.

Omh, ага, точно. Но там разбора секции кода не было.
 
O

Omh

Yakov
Погоди, ты хочешь сказать, что код таки декомпилируем?
Как я понял, он не декомпилируется в тот вид, в котором пишем мы в Designer'e, но декомпилируется в вызовы ВМ, которые при определённой сноровке легко прочесть.
Так?
 
T

TIA

Тулзу выкладывать не собираюсь, потому что есть еше люди, которые пишут коммерческий код на LS и считающие его недекомпилируемым.
Почему-то мне кажется, что это ваш коммерческий код. Я не прав? ;)
 
O

Omh

Я полагаю, там юзаются апишные ф-ии.
NSFFormulaDecompile может декопилить LS код?

А вообще, новости довольно плохие ;)

Может ещё найдётся способ из нотесного хеша получить обратно начальное значение?
 
Y

Yakov

Omh, так. Но декомпилятор из дизассемблера я пока делать не собираюсь.
TIA, я пишу коммерческий код на LS. А код тулзы - он для интереса (образовательные цели и все такое, см. disclaimer).
 
T

TIA

Как я понял он не декомпилируется в тот вид, в которм пишем мы, но декомпилируется в вызовы ВМ, которые при определённой сноровке легко прочесть.
Конечно, как и любой другой декомпилятор/дизассемблер. Комментов они не расставят ;)
 
Y

Yakov

Omh
Notes API используется для дампа бинарника библиотеки (ls-dump.exe). Код этой программы могу показать.
NSFFormulaDecompile придется использовать для декомпиляции прекомпилированных формул для Evaluate.
Все остальное - ручками и головой.
Может ещё найдётся способ из нотесного хеша получить обратно начальное значение?
А это о чем?
 
O

Omh

Yakov
Ясно, круто.

Насчёт хеша, это я к тому, что раньше был уверен, что скопиленный код недекомпилируем.
Эта стенка рухнула.

Второе, во что я верю, что из строки полученный команой HashPassword невозможно получить исходную строку.
Надеюсь на то, что это всё таки истина ;)
 
Y

Yakov

Omh, это смотря какой криптографический хеш используется. Надо бы поэкспериментировать и поискать, какие хеши уже взломаны. ;)
 
T

TIA

TIA, я пишу коммерческий код на LS. А код тулзы - он для интереса (образовательные цели и все такое, см. disclaimer).
Ок. Ок. Просто опрометчиво было полагаться на декомпилируемось.

А тулза, вроде как, показывала публичные декларации библиотек со скрытым кодом. Но декомпилированный псевдокод не показывала. Или это недокументированная фича?
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!