MSVBVM60.__vbaSetSystemError

Для неординарных вопросов. Если вы опытный программист, попавший в трудную ситуацию, — вам сюда.

Модератор: gaidar

Правила форума
Этот раздел не предназначен для того, чтобы вы адресовали свою проблему профессионалам.
Этот раздел предназначен для профессионалов, которые столкнулись с проблемой и не могут решить ее самостоятельно.
Если вы считаете себя профессионалом, а свою проблему сложной — вам сюда.
Если модератор посчитает, что вы ошиблись, то на первый раз он перенесет ваше сообщение в основной раздел без последствий для автора. Во второй раз тема будет закрыта, а автору будет выписано нарушение. В третий раз автор будет забанен.
uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

MSVBVM60.__vbaSetSystemError

Сообщение uni » 27.10.2007 (Сб) 9:19

Помогите, не могу понять куда дальше копать.

Проблема. Хочу написать (почти написал) native dll на VBasic'е 6.0. Эта dll подключается как бы в качестве плагина для Mathsoft Mathcad 11. Мне не нужна таблица экспорта. Библиотека расширяет набор функций математической системы, но делает это вызовом функции регистрации из другой dll при первичной загрузки программы.
Сейчас регистрация срабатывает и Mathcad добавляет функцию себе в набор пользовательских функций, но беда в том, что сразу после регистрации моя библиотека выгружается по ошибке. Я протрейсил все call'ы и дошёл до того места, где проблема, она оказалась в строке:
Код: Выделить всё
08C349D3  FF15 2C10C308     CALL DWORD PTR DS:[<&MSVBVM60.__vbaSetSystemError>]
На строчку выше идёт тот самый вызов функции регистрации. Этой функции передаётся 2 параметра: HINSTANCE dll и указатель на структуру, описывающую добавляемую функцию. Можно заметить, что указатель указывает на стек.
Вот кода модуля:
Код: Выделить всё
Option Explicit

Private Const DLL_PROCESS_ATTACH As Long = 1
Private Const DLL_PROCESS_DETACH As Long = 0
Private Const DLL_THREAD_ATTACH As Long = 2
Private Const DLL_THREAD_DETACH As Long = 3

' Глобальные константы
'// types to be used in declaration of the function's
'// arguments and of the return value
'#define COMPLEX_SCALAR  1
Public Const COMPLEX_SCALAR = 1
'#define COMPLEX_ARRAY   2
Public Const COMPLEX_ARRAY = 2
'#define STRING       8
Public Const CSTRING = 8 ' STRING - builtin type

'// your function will be passed a const char * pointer
'#define INFILE       13
Public Const INFILE = 13
'// an OUTFILE is like an INFILE except it allows you
'// to put your function on the left side of a := like
'// the WRITEPRN() builtin
'#define OUTFILE         14
Public Const OUTFILE = 14
'// use this structure to create a function

'#define MAX_ARGS        10
Public Const MAX_ARGS = 10

' Тип - описатель функции
Type FUNCTIONINFO
    lpstrName As String
    lpstrParameters As String
    lpstrDescription As String
    lpfnMyCFunction As Long
    returnType As Long
    nArgs As Long
    argType(MAX_ARGS - 1) As Long
End Type

'const void * CreateUserFunction( HINSTANCE, FUNCTIONINFO * );
Declare Function CreateUserFunction Lib "mcaduser.dll" (ByVal hInst As Long, FuncInfo As FUNCTIONINFO) As Long

' Описание тестовой функции пользователя
Global mcadVBTest01Info As FUNCTIONINFO

Function mcadVBTest01(lpOut As Long, lpIn As Long) As Long
' Комментарий
mcadVBTest01 = 0
End Function

Private Function ReturnMe(ByVal a As Long) As Long
  ReturnMe = a
End Function

Public Function DllMain(ByVal hInstDll As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long
Dim Res As Long
  'TODO:
  'Поместите здесь код инициализации библиотеки.

  Select Case fdwReason
  Case DLL_PROCESS_ATTACH
   With mcadVBTest01Info
      .lpstrName = "Test01"
      .lpstrParameters = "Parameters"
      .lpstrDescription = "Description"
      .lpfnMyCFunction = ReturnMe(AddressOf mcadVBTest01)
      .returnType = COMPLEX_SCALAR
      .nArgs = 1
      .argType(0) = COMPLEX_SCALAR
   End With
    Res = CreateUserFunction(hInstDll, mcadVBTest01Info)
    Err.Clear

    DllMain = 1 ' return TRUE
  Case DLL_PROCESS_DETACH
    '
   
  Case DLL_THREAD_ATTACH
    '
   
  Case DLL_THREAD_DETACH
    '
   
  End Select
End Function


Public Sub Exporting()
  'TODO:
  'Поместите тут Exports для каждой функции, которую нужно экспортировать.
  Exports "About", AddressOf MyProc
 
  Base &H400000    'Базу можно указать вручную, а можно не указывать.
 
End Sub

Public Sub MyProc()
'тут процедуры
End Sub



'TODO:
'Поместите тут экспортируемые функции.
'Не хотите тут - пожалуйста, помещайте где угодно. Но регистрацию Exports - здесь.
Можно заметить, что я использую местный код создания native dll.
Код: Выделить всё
CreateUserFunction(hInstDll, mcadVBTest01Info)
При регистрации возвращает некоторое не нулевое значение.

Вот фрагмент работы этого кода под Olly (на снимке выполнена команда CreateUserFunction() - .text:08C349CE, а далее код уходит в астрал ntdll):
Изображение

Вопрос к профи. Откудова растут ноги у ошибки? Мне нужно, чтобы dll не выгружалась хотя бы. Регистрация происходит успешно и Mathcad переходит в функцию, указанную в структуре, только вот, когда dll выгружена, то переходит он невесть куда, от чего возникает ошибка.
Что за функция SetSysytemError() ?

P.S. Я немного ошибся, функция регистрации ещё не выполнена. Она как раз собирается выполниться. Точка останова на ней более темная.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 9:44

А вот фрагмент заголовочного файла, по которому я ваял свой бейсиковский:
Код: Выделить всё
#ifndef _MCADINCL_H_
#define _MCADINCL_H_

#include <windows.h>

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
         
// complex scalar type
typedef struct tagCOMPLEXSCALAR {
    double real;
    double imag;
} COMPLEXSCALAR;
   
// this is the complex scalar type received from mathcad
typedef const COMPLEXSCALAR * const LPCCOMPLEXSCALAR;
// this is the complex scalar type that should be returned to mathcad
typedef COMPLEXSCALAR * const LPCOMPLEXSCALAR;
   

// complex array type
typedef struct tagCOMPLEXARRAY  {
    unsigned int rows;
    unsigned int cols;
    double **hReal; // hReal[cols][rows],  == NULL when the real part is zero
    double **hImag; // hImag[cols][rows],  == NULL when the imaginary part is zero
} COMPLEXARRAY;
   
// this is the complex array type received from mathcad
typedef const COMPLEXARRAY * const LPCCOMPLEXARRAY;   
// this is the complex array type that should be returned to mathcad
typedef COMPLEXARRAY * const LPCOMPLEXARRAY;


typedef struct tagMCSTRING {
   char *str;
}MCSTRING;

typedef const MCSTRING * const LPCMCSTRING;
typedef MCSTRING * const LPMCSTRING;


// types to be used in declaration of the function's
// arguments and of the return value
#define COMPLEX_SCALAR  1
#define COMPLEX_ARRAY   2
#define STRING         8


//
// File name variables. These are passed as const char *pointers
// if the string doesn't look like it has a path in it then
// the current working directory will be prepended to the string
// before it is passed to the user function.
//
//

// your function will be passed a const char * pointer
#define INFILE         13
// an OUTFILE is like an INFILE except it allows you
// to put your function on the left side of a := like
// the WRITEPRN() builtin
#define OUTFILE         14

// use this structure to create a function
#define MAX_ARGS        10

typedef LRESULT (* LPCFUNCTION ) ( void * const, const void * const, ... );   

typedef struct tagFUNCTIONINFO {
    char *  lpstrName;
    char *  lpstrParameters;
    char *  lpstrDescription;
    LPCFUNCTION lpfnMyCFunction;
    long unsigned int returnType;
    unsigned int nArgs;
    long unsigned int argType[MAX_ARGS];
} FUNCTIONINFO;

const void * CreateUserFunction( HINSTANCE, FUNCTIONINFO * );
Странно, что после вызова этой функции из mcaduser.dll стек не освобождается от параметров. То бишь, это получается не stdcall'овская функция? Сама стек не освобождает. Что же делать, если в этом причина? Попробовал вручную изменить регистр указателя стека. Не помогло.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 10:47

А-а, так нельзя с стеком. Это просто оболочка для вызова внешних функций из dll. Вот, блин, опыта нету, не знаю чего ожидать от кода. Здесь, мне кажется, используется какое-то неявное соглашение по признакам ошибки.
Как бы баланс стека соблюсти и обойти досадное ограничение. Будем экспериментировать.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 11:21

Вот, куда переходит код при вызове vbaSetSystemError()
Код: Выделить всё
660D63AB  56                PUSH ESI
660D63AC  FF15 60100066     CALL DWORD PTR DS:[66001060]                    ; ntdll.RtlGetLastWin32Error
660D63B2  FF35 B0FE1066     PUSH DWORD PTR DS:[6610FEB0]
660D63B8  8BF0              MOV ESI, EAX
660D63BA  FF15 AC100066     CALL DWORD PTR DS:[660010AC]                    ; kernel32.TlsGetValue
660D63C0  89B0 9C000000     MOV DWORD PTR DS:[EAX+9C], ESI
660D63C6  5E                POP ESI
660D63C7  C3                RETN
Ошибка получается, когда TlsGetValue() возвращает вместо валидного указателя ноль в регистре аккумуляторе (EAX). В результате чего мы пытаемся записать данные по нулевым адресам. Остаётся выяснить, каким образом получается, что блока данных потока нет.

При заполнении NOP'ами (MOV DWORD PTR DS:[EAX+9C], ESI) от этой неудачи уходим, но приходим к следующей.
Батва какая-то. Не думал, что так сложно будет.

P.S. TlsGetValue() используется очень часто во внутренних функциях VB. Избавиться NOP'ами не получится. Нужно искать причины внтури TlsGetValue(). Видимо блок данных потока существует, но после преобразования exe->dll, что-то где-то не допреобразовалось. Видимо нужно сначала поработать с exe-оригиналом и посмотреть на возвращаемые параметры там.
Последний раз редактировалось uni 27.10.2007 (Сб) 11:30, всего редактировалось 1 раз.

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 27.10.2007 (Сб) 11:30

парочка вопрососв:

1. На кой ляд понадобилось делать "Native DLL" на VB?
2. Кнопку "Правка" разве не видно?
3. а третий я пожалуй не буду задавать
Весь мир матрица, а мы в нем потоки байтов!

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 11:33

1. На кой ляд понадобилось делать "Native DLL" на VB?
2. Кнопку "Правка" разве не видно?
3. а третий я пожалуй не буду задавать
Я посещаю слишком много форумов, чтобы отслеживать правила или особенности каждого из них. Потому выработал для себя усреднённый стиль постинга и ему буду следовать.

Ответ на 1 вопрос. Потому что во всех остальных средах я уже такую написал (MSVC, C++Builder, Delphi, Win32Asm). Для комплекта не хватает.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 27.10.2007 (Сб) 11:57

Viper, возможно, Mathcad позволяет подключать в качестве расширений только Native-библиотеки. Так что причины могут быть.

uni, тем не менее, на этом форуме действуют не усредненные, а конкретные правила. И они предписывают не увлекаться топик-апом и использовать кнопку "Правка". Устное замечание.
Lasciate ogni speranza, voi ch'entrate.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 12:06

Viper, возможно, Mathcad позволяет подключать в качестве расширений только Native-библиотеки. Так что причины могут быть.
Да, это так. Это так давно. Кроме того самой фирмой описан только путь написания dll на MSVC и всё. Это способ расширения численных функций.

alibek, покажите мне, пожалуйста, пункт правила, на основании которого Вы вынесли мне замечание после всего нескольких моих постов. И конкретно, где именно я "увлёкся".

Ещё отмечу в качестве флуда, что считаю правки текста после нескольких постов дурным тоном, который мешает последующим форумчанам, если им будет это интересно, более подробно разбираться в мыслях постирующего и его опыте, на основании чего выводы могут быть разными.

Если можно, то всё следующее обсуждение только касаемо темы.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 27.10.2007 (Сб) 12:17

uni, третий пост, его можно было добавить во второй пост.
Плохо это или хорошо -- на этот счет есть разные точки зрения. На нашем форуме считается, что это лучше, чем несколько постов один за одним.
Пункт 6.16 Правил писал(а):16) Категорически не рекомендуется использовать топик-ап немедленно (в течении часа) после создания темы. Если у автора есть какие-нибудь уточнения, он может отредактировать свое сообщение, сделав пометку "Добавлено позже:".
Lasciate ogni speranza, voi ch'entrate.

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 27.10.2007 (Сб) 12:23

uni
В вопросе не разбираюсь, но рекомендую посмотреть эту тему.
Лучший способ понять что-то самому — объяснить это другому.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 12:26

alibek, учимся тогда считать:
12:47 - 11:44 = итого 1 час и 3 минуты. За это время я исследовал часть кода и понял, что ошибся слегка в посте, но не стал исправлять, чтобы форумчане думали: он тоже часто ошибается. На будущее.
Жду пояснений. :)

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 12:30

Antonariy, это пост, с которого я когда-то сюда пришёл. Меня удивило, что я так просто не могу скачать исходник, потому и зарегистрировался здесь. Около 1,5 лет тому назад. Сделал пару шагов, один в сторону - и тут же расстрел на месте.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 27.10.2007 (Сб) 13:07

Ок, устное замечание было ошибочным.
Lasciate ogni speranza, voi ch'entrate.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 14:39

Проехали. Идём далее. Сеть говорит, что точка входа exe содержит вызов: ThunRTMain(&RT_MainStruct);
Мы, как я понял, честно игнорируем этот вызов. Возможно в этом и есть беда. Структура, ссылка на которую передаётся в движок VB, возможно содержит некоторые данные начальной установки. Если мы не проинициализируем некоторые структуры, которые движок использует в процессе работы, то постоянно будем вываливаться.
Интересно, кто-нить реально использовал местный код Native DLL про прямому назначению? Не просто переделать exe->dll, тут ничего сложного нет, я и не такое ваял, а заставить получившуюся библиотеку фунциклировать в целевом приложении. Заставить функциклировать функции из библиотеки VB так как они должны работать. Ведь переделка PE файла ещё далеко не означает, что native dll будет работать как нужно. Есть ещё ряд работ, которые нужно будет проделать и которые зависят от целевого приложения, среды самой dll, да и ещё неизвестных факторов (наличие лицензии, например).

Понадеялся я зря выходит. Тут ещё пахать и пахать.

P.S. Я опять ошибся. Проект, по-видимому, предназначался для пользования в самом VB, а не сторонних языках и средах. Не удивительно, что кое-чего не работает, зато удивительно, что вообще что-то работает. Надо бы пинка где-то дать движку.
В точке входа сначала надо вызывать движок, но блин каким-то хитрым способом, чтобы он передал управление на код регистрации функции. Да-а, в опкодах и-то приятней программить не говоря уже об masm'е. Плохо, когда нету документации.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 15:43

uni
Идея мертва. GSerg-овский NativeDLL-шаблон неработоспособен. Баги, возникающие в нём носят исключительно случайных и непредсказуемый характер.

ЗЫ. Что за дрянь? Когда я открыл тему в ней было лишь два поста.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 16:15

Хе-хе.
Ну, я не был бы столь категоричен. Мне не нужна полноценная супер-пупер dll. Мне не нужна вообще секция экспорта, поэтому весь код, посвящённый добавлению оной можно выкинуть. Вот точку входа я бы не стал так скоро изменять на DllMain().
Суть в том, чтобы использовать математические "способности" VB и только их. Никаких строк мне не нужно. Небольшая работа со структурами ещё. Ах да, есть ещё одна проблема - передача переменного количества параметров. Callback функция описана именно так.

Т.о. я бы хотел использовать "транслятор" msvbvm60.dll по-минимуму. Судя по трейсингу в Olly ничего такого особенного msvbvm60 не выкидывает. Хоть я трейсил не много функций ошибки возникали только в одном месте пока. Я озвучил её выше. У меня уже есть успешный опыт приделывания гораздо более сложной фичи к Mathcad, там exe переделывался в dll правда ручками и работал в параллельном потоке, но тоже был движок, правда в совсем другом смысле.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 16:23

Суть в том, чтобы использовать математические "способности" VB и только их. Никаких строк мне не нужно. Небольшая работа со структурами ещё

Я полагаю, что обломы всё-равно ждут тебя.

Ах да, есть ещё одна проблема - передача переменного количества параметров. Callback функция описана именно так.

Ты не сможешь сделать такую функцию. stdcall не предусматривает переменной число аргументов. cdecl же не поддерживается в VB.


Т.о. я бы хотел использовать "транслятор" msvbvm60.dll по-минимуму.

"Транслятор" ? :roll:
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 16:33

"Транслятор"ом я назвал её условно. Тут вот:
http://www.reteam.org/papers/e46.pdf
движком называют (Thunder Runtime Engine), что видимо тоже условно, если не считать функцию трансляции p-кода движком. Тогда всё перемешивается и вроде бы всё уместно. Если скажите как правильно называть, буду следовать устоявшимся терминам. Я тут не специалист по бейсику, запускал его визуальный потомок только с десяток раз.

Ваши слова, конечно, уменьшили мол пыл. Ещё вопрос. А как на счёт функции wsprintf()? С ней получалось работать и как?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 16:42

"Транслятор"ом я назвал её условно. Тут вот:
http://www.reteam.org/papers/e46.pdf
движком называют (Thunder Runtime Engine), что видимо тоже условно, если не считать функцию трансляции p-кода движком.
Если скажите как правильно называть, буду следовать устоявшимся терминам

Её называют "рантайм"-ом.


А как на счёт функции wsprintf()?

Это очень хорошая функция. Но причём она тут? Её нет в VB. Её нет в рантайме. Это к тому же cdecl-функция, если речь идёт об экспорте msvcrt. Её не вызвать просто-так из VB.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 16:46

wsprintf() это не просто cdecl функция, а таковая с переменным количеством параметров. Я подумал, что если из VB кто-то научился ею пользоваться (а это редкое отступления в наборе Win32API - тот набор, который входит в стандартные системные dll), то технику работы с переменным количеством аргументов и стеком можно было бы подсмотреть.
Вот причём тут она. Если я что-то пишу, то это тоже не просто так.
Код: Выделить всё
[C:\WINDOWS\system32]$ dumpbin /exports user32.dll | grep wsprintf
                729  2D8   wsprintfA  (0000A2DE)
                730  2D9   wsprintfW  (0000A862)
Последний раз редактировалось uni 27.10.2007 (Сб) 16:48, всего редактировалось 1 раз.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 16:48

uni
Ну, положим, я научился. Что мешает нам (тебе?) сформировать стек ручками и сделать call ?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 16:53

Ну, положим я научился? Что мешает нам сформировать стек ручками и сделать call ?
Мне нужна обратная операция, "разобрать стек ручками", т.к. моя численная функция, расширяющая возможности Mathcad, будет вызываться точно как wsprintf(). Моя задача сбалансировать стек и достать параметры, чтобы при этом небыло краха. Вернуть нужно либо ссылку на массив, либо просто заполнить поля структуры, причём оба указателя передаются внутрь функции пользователя.
Ну, до этого ещё нужно довести не работающий код загрузки dll. Точнее убрать ошибку, которая её выгружает. Всё остальное работает как нужно пока.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 16:59

uni
На VB нельзя сделать naked-функцию, поэтмоу VB Непременно что-то будет делать со-стеком, до того, как что-то можешь сделать ты.

С другой стороны, ты можешь написать callback-переходник на асме, который будет "разбирать cdecl-call-стековый-кадр" и переделывать его в stdcall-call-стековый-кадр, уже потом вызывать (вызывать джампом - можно и call-ом, но если делать jump-ом, не произойдёт лишних возвратов) VB-шную функцию. Та, в свою очередь, получит в стеке то, что и ожидаешь - нормальный стековый кадр.

Т.е. ты можешь написать много VB-обработчиков - для 1 аргумента, для двух, трёх.

А асм переходник будет смотреть на число аргументов, класть их в стек в обратном порядке и вызывать нужную (в зависимости от числа аргументов) функцию.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 17:05

"Написать асм-переходник" в каком виде? Это можно автоматизировать?
Если внедрять асм код, то нужно будет править таблицу перемещаемых элементов. Навряд ли получится написать чисто относительный код.

А-а, добавить dll ещё с переходником?

P.S. Мне тут в голову ещё одна мысль пришла. Мне лишь нужно, чтобы код подгрузился в адресное пространство моего процесса и выполнил начальную регистрацию, после чего не выгружался, т.е. Callback функция висела в памяти. Вот если бы подгрузить модуль exe в память и создать || поток, т.е. просимулировать первые две асм-команды в exe файле. Потоку как раз нужна функция с одним параметром. Тогда и dll на vb не нужна мне. Рантайм библиотека сама всё сделает, проинициализирует, а в конце мы просто заморозим выполнение потока. Это не помешает основной программе обращаться к нужному адресу. Накладки тут возможны. Но чем не вариант?

P.S. Да, я тут вспомнил, что Дан Эпплман в приложении к своей книге "Win32 API и Visual Basic. Для профессионалов" включил ряд файлов, в одном и которых можно найти следующую конструкцию (E:\ARTICLES\VBDEV\SOURCE\APIDECS.BAS):
Код: Выделить всё
Declare Function wvsprintf% Lib "User" (ByVal lpszOutput$, ByVal lpszFormat$, lpvArglist%)
Тут в общем наглядно видно, что возможно дальнейшее использование параметров. Вот в действительности возможно ли? Или это просто "общий вид"?

А-а, эта нормальная. Тут буковка v есть. stdcall.
Последний раз редактировалось uni 27.10.2007 (Сб) 17:49, всего редактировалось 1 раз.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 17:48

"Написать асм-переходник" в каком виде?

Пишут асм-переходник обычно ввиде асм-кода. Потом компилируют, и получают просто код. Потом с ним что-то делают.

Если внедрять асм код, то нужно будет править таблицу перемещаемых элементов. Навряд ли получится написать чисто относительный код.

Куда внедрять? Что есть таблица перемещаемых элементов (предположение: reloc-и?).

P.S. Мне тут в голову ещё одна мысль пришла. Мне лишь нужно, чтобы код подгрузился в адресное пространство моего процесса и выполнил начальную регистрацию, после чего не выгружался, т.е. Callback функция висела в памяти.

Код "подгружается" в АП процесса при загрузки или при LoadLibrary. В чём проблема?

Вот если бы подгрузить модуль exe в память и создать || поток, т.е. просимулировать первые две асм-команды в exe файле.

Не понял. Что значит "просимулировать асм-команды" ?

Потоку как раз нужна функция с одним параметром. Тогда и dll на vb не нужна мне. Рантайм библиотека сама всё сделает, проинициализирует, а в конце мы просто заморозим выполнение потока. Это не помешает основной программе обращаться к нужному адресу. Накладки тут возможны. Но чем не вариант?

Всё равно не понял.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 18:02

Когда мы подгружаем по LoadLibrary(), то выполняется код в точке входа DllMain(). Туда передаётся три параметра. При создании потока по CreateThread() передаётся адрес функции и указатель (или просто число) - один параметр. Если мы имеем дело со стартап кодом сишным, то там функция start() имеет один параметр, который не используется, что делает возможным запускать потоки и передавать в качестве параметра указатель на функцию start() с нулевым указателем, к примеру. Это я сам делал.

Точка входа VB exe-файла имеет вид:
Код: Выделить всё
.text:004014BA ThunRTMain      proc near               ; CODE XREF: .text:004014C5p
.text:004014BA                 jmp     ds:__imp_ThunRTMain
.text:004014BA ThunRTMain      endp
.text:004014BA
.text:004014C0 ; ---------------------------------------------------------------------------
.text:004014C0                 push    offset aVb5     ; "VB5!"
.text:004014C5                 call    ThunRTMain
.text:004014C5 ; ---------------------------------------------------------------------------
Первые две команды:
1) Толкаем указатель на структуру в стек (единственный параметр)
2) Вызываем функцию "рантайм" (не звучит).
То же на Си:
Код: Выделить всё
ThunRTMain(&RT_MainStruct);
Дальнейшие дествия определяются уже "рантаймом". Можно сделать так. Создать поток, в качесте функции передать указатель на __imp_ThunRTMain() а аргумент нужно вычислить по первой команде push'а. Указатель абсолютный, поэтому тут нужно быть осторожным.
Вместо того, чтобы выполняться в main thread, рантайм будет выполняться в потоке. Возможны коллизии, только опыт скажет возможно ли это.

Если делать в потоке, то я могу прямо в функции Main() на VB написать функцию регистрации и заморозить текущий поток. Мы ведь в общем адресном пространстве. Теперь Mathcad может обращаться к функции. При этом он будет использовать уже проинициализированные все нужные структуры для рантайма. По идее будет работать. После закрытия программы потоки тоже завершатся.

Примерно так. Когда я говорил про свой опыт, то имел в виду такую реализацию, причём делал всё вручную, буквально в машинных кодах, что в общем при навыке не так сложно.

P.S. Да, релоки - это и есть таблица перемещаемых элементов:
http://www.samag.ru/art/06.2004/06.2004_08.pdf
Читаем классиков и будем увереннее.

Цитата:
Потом компилируют, и получают просто код. Потом с ним что-то делают

Просто так такой код использовать нельзя. В "плоском виде", вставленный (скопированный) в адресное пространство процесса, он "уложит" его при первом вызове в большинстве случаев. Линкер добавляет в выходной файл секцию релоков, чтобы при загрузке с другим ImageBase код продолжал работать. В общем, это не так страшно Smile править релоки можно и нужно при их наличии, только автоматизировать это будет сложновато на первый взгляд.

Потому я и спрашиваю, а что конкретно делают с асм кодом. Делать то можно всякое. Мы итак уже вирус почти написали.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 20:03

DllMain это сугубо сишный термин. Не употребляй его. Употребляй термин "точка входа".


Код: Выделить всё
.text:004014BA ThunRTMain      proc near               ; CODE XREF: .text:004014C5p
.text:004014BA                 jmp     ds:__imp_ThunRTMain
.text:004014BA ThunRTMain      endp
.text:004014BA
.text:004014C0 ; ---------------------------------------------------------------------------
.text:004014C0                 push    offset aVb5     ; "VB5!"
.text:004014C5                 call    ThunRTMain
.text:004014C5 ; ---------------------------------------------------------------------------


Фи. Масмовский синтаксис. Нет, я конечно понимаю, что вкусы и предпочтения у всех разные, но я ни при каких условиях не перенесу это.


Первые две команды:
1) Толкаем указатель на структуру в стек (единственный параметр)
2) Вызываем функцию "рантайм" (не звучит).

Не надо разжевывать мне асм-код. Я и сам его прекрасно понимаю.


Дальнейшие дествия определяются уже "рантаймом". Можно сделать так. Создать поток, в качесте функции передать указатель на __imp_ThunRTMain() а аргумент нужно вычислить по первой команде push'а. Указатель абсолютный, поэтому тут нужно быть осторожным.
Вместо того, чтобы выполняться в main thread, рантайм будет выполняться в потоке. Возможны коллизии, только опыт скажет возможно ли это.

Если делать в потоке, то я могу прямо в функции Main() на VB написать функцию регистрации и заморозить текущий поток. Мы ведь в общем адресном пространстве. Теперь Mathcad может обращаться к функции. При этом он будет использовать уже проинициализированные все нужные структуры для рантайма. По идее будет работать. После закрытия программы потоки тоже завершатся.

Примерно так. Когда я говорил про свой опыт, то имел в виду такую реализацию, причём делал всё вручную, буквально в машинных кодах, что в общем при навыке не так сложно.

Здесь что-то написано, но я так и не понял что. Функция регистрации какая-то. Потоки, mathcad.

Ты мог бы сначала объяснить какова цель сего извращенства, а потом уже более подробно описывать извращенство?

P.S. Да, релоки - это и есть таблица перемещаемых элементов:
http://www.samag.ru/art/06.2004/06.2004_08.pdf
Читаем классиков и будем увереннее.

Если они релоки трактуют как "таблица перемещаемых элементов", то по моему, они не классики, а долбодятлы. Потому что это не таблица каких-то там элементов (элементов? каких ещё элементов?). Это таблица, в которой содержатся адреса мест в коде, где используется абсолютная адресация. Но pdf файл выполнен красиво, а значит, имеет право быть прочитанным.


Просто так такой код использовать нельзя. В "плоском виде", вставленный (скопированный) в адресное пространство процесса, он "уложит" его при первом вызове в большинстве случаев.


С чего бы это?

Код: Выделить всё
mov eax, [esp+04]
add eax, [esp+08]
retn 8


Если я просто вставлю этот код в АП процесса и выполню его, он ничего не уложит. И любой другой код, ничего не уложит, если будет правильным.

Линкер добавляет в выходной файл секцию релоков, чтобы при загрузке с другим ImageBase код продолжал работать.

И?


В общем, это не так страшно Smile править релоки можно и нужно при их наличии, только автоматизировать это будет сложновато на первый взгляд.

Судя по "Smile" этот текст - копипаст откуда-то. Вопрос: к чему тут этот копипаст?

Потому я и спрашиваю, а что конкретно делают с асм кодом. Делать то можно всякое. Мы итак уже вирус почти написали.

Асм код компилируют, вот что с ним делают. Получают просто код. Native-код. Native-код выполняют.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 27.10.2007 (Сб) 21:05

Нда. Пояснять будет трудно. Ваша самобытность тому препятствием будет.
Я же не обижаюсь, когда Вы MSVBVM60.dll называете просто "рантаймом". Более того прошу меня научить. А называть "долбодятлом" как раз такой долбодятел и может. Хе-хе.
Если чуть приложить здравого смысла MSVBVM60.dll - Microsoft Visual Basic Virtual Machine 6.0 - что тут про рантайм есть? Ничего. Если Вы хотите находить общий язык с кем-то, то нужно уважать стандарты и обозначения, принятые создателями, самой фирмой или теми группами людей, который съели собаку в каком-то деле.
Я, по крайней мере, попытался (как было видно выше) следовать такой установки, чего, конечно, ожидал и от Вас.

Моё изложение очень кратко и сумбурно оказалось для Вас изложенным. Постараюсь позже этот недостаток исправить.

Вместо термина релоки, могу предложить термин relocation section от ещё одного "долбодятла" (Jeffrey Richter). Либо вообще перейти на английский. Можно также называть "правки" (fixups) как в шестой ревизии описания PE формата. Если же мы закачаем
Visual Studio, Microsoft Portable Executable and Common Object File Format Specification Revision 8.0 - May 16, 2006
, то увидим, что тамошние долбодятлы для тутошних описали сабж как "The base relocation table", что, видимо, для Вас является "труднопереводимым идеоматическим выражением".

Если Вы не хотите понимать источники и принимать их, то просьба учитывать при этом не желание следовать Вашим путём других долбодятлов.

Smile взялся, т.к. я случайно запостил 2 раза одно и тоже с небольшим исправлением. Поэтому просто скопировал, удалив лишний пост. Что вставилось, то вставилось.
Фи. Масмовский синтаксис.
Это синтаксис IDA. Что он выдал, то и вставляю. Если бы я переделывал под masm, то выглядело бы что-то вроде такого:
Код: Выделить всё
;----------------------------------------------------------------------------
;                           MCadUserDLL.asm
;----------------------------------------------------------------------------

.386
.model flat,stdcall

option casemap:none
comment #
   Пример является тестовой пользовательской библиотекой
для программы Mathcad. #

; -=[ Основные библиотеки ]=-
include windows.inc
;include user32.inc
include kernel32.inc

; -=[ Дополнительные библиотеки ]=-
include mcaduser.inc ; файл описания библиотеки mcaduser.lib

;includelib user32.lib
includelib kernel32.lib
includelib mcaduser.lib

; -=[ Макросы ]=-
; Аналог оператора return
return  macro arg
mov eax, arg
ret
ENDM

; -=[ Объявления функций ]=-
;typedef LRESULT (* LPCFUNCTION ) ( void * const, const void * const, ... );
mcadTestFunc proto c :DWORD, :DWORD, :VARARG

; -=[ Секция инициализированных данных ]=-
.data
;MsgBoxCaption  db "Iczelion Tutorial No.2",0
;MsgBoxText     db "Win32 Assembly is Great!",0
FuncName       db "TestFunc",0
ArgListStr     db "Arg",0
FuncDescr      db "Test function",0

; Структура данных, описывающая функцию
TestFuncInfo   FUNCTIONINFO <FuncName,\
                             ArgListStr,\
                             FuncDescr,\
                             mcadTestFunc,\
                             COMPLEX_SCALAR,\      ; тип выходного параметра - скаляр
                             1,\                   ; функция имеет один входной параметр
                             { COMPLEX_SCALAR }>   ; типы входных параметров

; -=[ Секция кода ]=-
.code                       
DllMain proc hInstDLL: HINSTANCE, dwReason: DWORD, lpReserved: LPVOID
.if     dwReason==DLL_PROCESS_ATTACH
; DLL проецируется на адресное пространство процесса
  invoke CreateUserFunction, hInstDLL, addr TestFuncInfo

.elseif dwReason==DLL_THREAD_ATTACH
; создаётся поток

.elseif dwReason==DLL_THREAD_DETACH
; поток корректно завершается

.elseif dwReason==DLL_PROCESS_DETACH
; DLL отключается от адресного пространства процесса

.endif

; используется только для DLL_PROCESS_ATTACH
return TRUE

DllMain Endp

mcadTestFunc proc c OutVar: LPCOMPLEXSCALAR, InVar: LPCCOMPLEXSCALAR, VarList:VARARG

; Тестовое сообщение
; invoke MessageBox, NULL, addr MsgBoxText, addr MsgBoxCaption, MB_OK

comment # TODO: Оформить в виде макроса присвоение переменной типа COMPLEXSCALAR
; значения типа double

SetReal    OutVar, 1.0
SetImage   OutVar, 1.0
SetCmplx   OutVar, 1.0, 2.0

SetReal macro arg, num
mov  eax, [arg]
mov  dword ptr [eax], hiword num
mov  dword ptr [eax + 4], loword num
endm

LOWORD   MACRO       ;; Retrieves the low word from double word lParam

   mov   eax,lParam
   and   eax,0FFFFh   ;; Set cxClient to low word

   ENDM

HIWORD   MACRO       ;; Retrieves the high word from double word lParam

   mov   ebx,lParam
   shr   ebx,16      ;; Shift 16 for high word to set cyClient to high word

   ENDM
#

; OutVar->real = 1.0;
mov  eax, [OutVar]
mov  dword ptr [eax], 0
mov  dword ptr [eax + 4], 3FF00000h

; OutVar->imag = 2.0;
mov  dword ptr [eax + 8], 0
mov  dword ptr [eax + 0Ch], 40000000h

; Возвращаем признак успешного выполнения функции
return 0

mcadTestFunc endp

End DllMain
Это пример модуля той же библиотеки, которую я хочу наваять на VB.

Про извращенства позже.

P.S. И ещё, ребят, ещё пара замечаний не в тему и мне будет казаться, что тут отвечает народ, имеющий некоторый комплекс. Будьте проще.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16475
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Сообщение Хакер » 27.10.2007 (Сб) 22:42

Я же не обижаюсь, когда Вы MSVBVM60.dll называете просто "рантаймом". Более того прошу меня научить. А называть "долбодятлом" как раз такой долбодятел и может. Хе-хе.

Все называют его рантаймом.


Если чуть приложить здравого смысла MSVBVM60.dll - Microsoft Visual Basic Virtual Machine 6.0 - что тут про рантайм есть?

Если бы ты меньше выпендривался, а больше бы уделял изучению истории развития VB, то знал бы, что раннии версии VB выполнялись исключительно под виртуальной машиной. Поэтому исторически сложилось, что этот файл называется именно так.

Для VB6 и проекта, скомпилированного в Native-код это такой же рантайм, как msvcrt (microsoft visual c++ run-time) для приложений, скомпилированных на Microsoft Visual C++.

Моё изложение очень кратко и сумбурно оказалось для Вас изложенным. Постараюсь позже этот недостаток исправить.

Не стоит. Ввиду того, что мне довелось получить от тебя очень приятный комплимент, я больше не испытываю интереса к этой теме и желания помочь тебе.


Вместо термина релоки, могу предложить термин relocation section от ещё одного "долбодятла" (Jeffrey Richter). Либо вообще перейти на английский.

Нда... ты предлагаешь вообще перейти на английский. А скажи - relocation section - это не английский?
Но дело не в этом. Рихтера я, наоборот, долбодятлом не считаю, а испытываю к нему уважение, в отличие от автора того pdf-шника.

Если же мы закачаем
Visual Studio, Microsoft Portable Executable and Common Object File Format Specification Revision 8.0 - May 16, 2006

, то увидим, что тамошние долбодятлы для тутошних описали сабж как "The base relocation table", что, видимо, для Вас является "труднопереводимым идеоматическим выражением".

Продолжаешь говорить ерунду. Кажется, речь шла о русскоязычном термине. Какого фига ты уже второй раз предлагаешь мне англоязычный вариант? Я не спорил, что вариант "relocation table" правильный.

Если Вы не хотите понимать источники и принимать их, то просьба учитывать при этом не желание следовать Вашим путём других долбодятлов.

Если ты делаешь вывод, что я действительно таким образом отношусь ко всем источникам, то это ещё один довод в пользу того, что лучше бы мне закончить с тобой этот разговор.

Это пример модуля той же библиотеки, которую я хочу наваять на VB.

А по моему это какой-то шаблон, из туториала Iczelion-а, взятый с WASM-а.

P.S. И ещё, ребят, ещё пара замечаний не в тему и мне будет казаться, что тут отвечает народ, имеющий некоторый комплекс. Будьте проще.

Забавно звучит. Как-то так нагло и дерзко.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

uni
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 105
Зарегистрирован: 05.05.2006 (Пт) 15:24
Откуда: Екатеринбург

Сообщение uni » 28.10.2007 (Вс) 6:52

Ну что же, раз так, то давайте расстанемся. На будущее, признаком хорошего тона является неТЫкание своему оппоненту, соответственно, обратное ТЫкание - признак изначального неуважения. Это моё личное понимание культуры общения образованных людей.

На этом с Вами всё.

Я бы хотел, всё-таки, чтобы обсуждали не меня, чёрт со мной, а проблему. Я сам попробую реализовать, то, что Хакеру сумбурным показалось и посмотреть, что получится. Дело в том, что с локальной памятью потока я ещё не сталкивался, а (неверное) использование функции TlsGetValue() явно указывает на это, ошибка появляется, насколько я понял, именно там.

След.

Вернуться в Раздел для Профессионалов

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

    TopList