Как сменить текущую директорию?

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Как сменить текущую директорию?

Сообщение arthur2 » 20.06.2019 (Чт) 17:43

Я в Аддине. Хочу, чтобы когда пользователь закрыл проект и открывает новый, диалог открывался с папкой проекта, а не с папкой vb98.

SetCurrentDirectory, ChDrive и ChDir не помогли - они срабатывают, но у диалоговых окон бейсика, похоже, собственное представление о том, какая директория сейчас текущая.
Артур
 
   

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: Как сменить текущую директорию?

Сообщение bon818 » 21.06.2019 (Пт) 5:59

Не совсем понял, но я указываю в свойствах ярлыка к VB6.EXE "Рабочая папка: Рабочий стол"
Последний раз редактировалось bon818 21.06.2019 (Пт) 7:42, всего редактировалось 1 раз.

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 21.06.2019 (Пт) 6:54

Ну как "грязное" решение можно занулить DWORD по адресу 0059F29C, по которому хранится адрес строки с папкой проекта. После этого будет открываться текущая директория.
UA6527P

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 7:45

arthur2 писал(а):SetCurrentDirectory, ChDrive и ChDir не помогли - они срабатывают, но у диалоговых окон бейсика, похоже, собственное представление о том, какая директория сейчас текущая.

Во-первых, не у диалоговых окон бейсика, а диалоговых окон Common Dialog. Во-вторых, ты так говоришь, как будто задание текущей директории — единственная возможность сообщить Common Dialog'у папку, которую он должен показывать изначально. Вот мы когда заказываем показ диалога открытия или сохранения файла, мы можем задать заголовок диалога, список фильтров по типу/расширения файла, разные флаги вроде того, должен ли Common Dialog давать указать только существующий файл, должен ли отображаться чекбокс «Только для чтения», при открытии ярлыка возвращаться ли путь к lnk-файлу, или же надо заглянуть внутрь lnk и вместо пути к lnk вернуть путь к тому объекту, на который ссылается этот ярлык. И почему-то всё-всё-свё это мы явно указываем, а вот изначальную папку можно задать только лишь меняя curdir.
Естественно, что путь этот тоже можно задать явно, и Common Dialog обращается к GetCurrentDirectory только если явно не было указано ничего.

The trick писал(а):Ну как "грязное" решение можно занулить DWORD по адресу 0059F29C, по которому хранится адрес строки с папкой проекта. После этого будет открываться текущая директория.

Очень-очень грязное решение, ведь билдов VB6.EXE множество, и нет никакой гарантии, что нам попадётся именно тот билд, где где второй DWORD переменной g_Dlg_filerepLastPathFiles класса CFileRep окажется именно по адресу 0059F29C. Занулять по жестко заданному адресу — выстрел вслепую.

Более стабильное и предсказуемое решение: перехватывать comdlg32-шную функцию GetOpenFileNameA и подменять значение поля структуры OPENFILENAMEA на нужный путь.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 9:19

Хакер писал(а):Естественно, что путь этот тоже можно задать явно, и Common Dialog обращается к GetCurrentDirectory только если явно не было указано ничего.


При чтении документации на OPENFILENAME оказалось, что алгоритм выбора изначальной папки куда более замудрёный:
lpstrInitialDir
Type: LPCTSTR

The initial directory. The algorithm for selecting the initial directory varies on different platforms.
Windows 7:
  1. If lpstrInitialDir has the same value as was passed the first time the application used an Open or Save As dialog box, the path most recently selected by the user is used as the initial directory.
  2. Otherwise, if lpstrFile contains a path, that path is the initial directory.
  3. Otherwise, if lpstrInitialDir is not NULL, it specifies the initial directory.
  4. If lpstrInitialDir is NULL and the current directory contains any files of the specified filter types, the initial directory is the current directory.
  5. Otherwise, the initial directory is the personal files directory of the current user.
  6. Otherwise, the initial directory is the Desktop folder.
Windows 2000/XP/Vista:
  1. If lpstrFile contains a path, that path is the initial directory.
  2. Otherwise, lpstrInitialDir specifies the initial directory.
  3. Otherwise, if the application has used an Open or Save As dialog box in the past, the path most recently used is selected as the initial directory. However, if an application is not run for a long time, its saved selected path is discarded.
  4. If lpstrInitialDir is NULL and the current directory contains any files of the specified filter types, the initial directory is the current directory.
  5. Otherwise, the initial directory is the personal files directory of the current user.
  6. Otherwise, the initial directory is the Desktop folder.


bon818 писал(а):Не совсем понял, но я указываю в свойствах ярлыка к VB6.EXE "Рабочая папка: Рабочий стол"

Отличный совет! Поменял себе на g:\dev и теперь буду делать меньше телодвижений.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Как сменить текущую директорию?

Сообщение ger_kar » 21.06.2019 (Пт) 9:28

Хакер писал(а):Более стабильное и предсказуемое решение: перехватывать comdlg32-шную функцию GetOpenFileNameA и подменять значение поля структуры OPENFILENAMEA на нужный путь.
А оконными сообщениями можно управлять этими диалоговыми окнами? Может как то через оконное сообщение можно путь установить?
Бороться и искать, найти и перепрятать

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 9:31

ger_kar писал(а):А оконными сообщениями можно управлять этими диалоговыми окнами? Может как то через оконное сообщение можно путь установить?

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

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Как сменить текущую директорию?

Сообщение ger_kar » 21.06.2019 (Пт) 9:38

bon818 писал(а):Не совсем понял, но я указываю в свойствах ярлыка к VB6.EXE "Рабочая папка: Рабочий стол"
Хакер писал(а):Отличный совет! Поменял себе на g:\dev и теперь буду делать меньше телодвижений.
Да совет действительно классный. И самое интересное, что решение элементарное и лежало на поверхности, но тем не менее применить его голова не додумалась :roll: Я кстати раньше делал немного по другому. В папку VB98 добавлял ярлык, кликая который перемещался в нужную папку.
Бороться и искать, найти и перепрятать

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: Как сменить текущую директорию?

Сообщение ger_kar » 21.06.2019 (Пт) 9:44

Хакер писал(а):Зачем?
Кто будет слать оконное сообщение, если с момента, как диалог появился (и создалось окно) и до момента, когда окно перестанет существовать, управление уходит из нашего кода и выполняется оконный цикл внутри comdlg32.dll?
Можно это делать их отдельного потока, или даже процесса. Т.е. можно предварительно запускать другое приложение (или скрипт), который будет ждать окно и путем оконного сообщения устанавливать нужный путь. Перехватывать функцию из VB6, то еще геммор. Для этого нужно будет отдельную Dll лепить. А со скриптом все гораздо проще. Если конечно оконными сообщениями можно путь подправить.
Бороться и искать, найти и перепрятать

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 10:57

ger_kar писал(а):Можно это делать их отдельного потока, или даже процесса. Т.е. можно предварительно запускать другое приложение (или скрипт), который будет ждать окно и путем оконного сообщения устанавливать нужный путь.

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

ger_kar писал(а):Перехватывать функцию из VB6, то еще геммор. Для этого нужно будет отдельную Dll лепить.

Никакого геморроя нет и близко.

Код: Выделить всё
Declare Function GetOpenFileNameA Lib "comdlg32.dll" (ByRef lpofn as OPENFILENAME) As Long

PutMem4 ptr_to_func_ptr, AddressOf GetOpenFileNameA_handler

Function GetOpenFileNameA_handler(ByRef lpofn as OPENFILENAME) As Long
     lpofn.lpstrInitialDir = подмена
     GetOpenFileNameA_handler = GetOpenFileNameA(lpofn)
End Function


И вся любовь!

В отличие от того, что ты предлагаешь (те же потоки). Отдельная DLL — я не понял, для чего. Вообще-то человек пишет Add-in, а это и так отдельная DLL.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 21.06.2019 (Пт) 13:12

Хакер писал(а):Занулять по жестко заданному адресу — выстрел вслепую.

Можно просто проанализировать билд по сигнатурам, и получать этот адрес (сорри у меня нет символов как у Хакера, поэтому почти голый асм):
path_set.png
path_set.png (25.32 Кб) Просмотров: 6231

Выделенный offset + 4 - адрес нужной переменной. Думаю по сигнатуре
Код: Выделить всё
C7 05 XX XX XX XX 12 C3 02 00 50 56 6A 01 56 56
56 56 56 56 68 XX XX XX XX 6A 64

будет достаточно, хотя нужно тестить на разных билдах. Я бы так сделал если для общего использования.

Хакер писал(а):Более стабильное и предсказуемое решение: перехватывать comdlg32-шную функцию GetOpenFileNameA и подменять значение поля структуры OPENFILENAMEA на нужный путь.

Тут тоже не все так просто, к примеру в моем билде адреса получаются динамически и хранятся по фиксированному адресу. А если перехватывать внутри comdlg32 то там придется отслеживать откуда вызов пришел - мало ли кто вызывал GetOpenFileNameA с произвольными аргументами.
UA6527P

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 14:36

The trick писал(а):Можно просто проанализировать билд по сигнатурам, и получать этот адрес (сорри у меня нет символов как у Хакера, поэтому почти голый асм):

Будешь собирать все сигнатуры, включая всякие китайские билды VB6.EXE?
Сигнатуры — это крайняя мера, когда уже ничего другого применить нельзя. А здесь можно.

The trick писал(а):Тут тоже не все так просто, к примеру в моем билде адреса получаются динамически и хранятся по фиксированному адресу. А если перехватывать внутри comdlg32 то там придется отслеживать откуда вызов пришел - мало ли кто вызывал GetOpenFileNameA с произвольными аргументами.

Да, динамически. Но это этот отложенный импорт происходит при первом обращении к Common Dialog, а не при старте среды и не до загрузки Add-in'ов. А поскольку Add-in'ы загружаются раньше, у Add-in'а есть возможность перехватить GetProcAddress (правкой ячейки IAT — то есть в одну строчку) и подсунуть вместо GetOpenFileNameA свой адрес:

Код: Выделить всё
Declare Function GetOpenFileNameA Lib "comdlg32.dll" (ByRef lpofn as OPENFILENAME) As Long
Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hMod as long, ByVal ProcOrOrd as Long) As Long

PutMem4 iat_cell_for_GPA, AddressOf GetProcAddress_handler

Function GetOpenFileNameA_handler(ByRef lpofn as OPENFILENAME) As Long
     lpofn.lpstrInitialDir = подмена
     GetOpenFileNameA_handler = GetOpenFileNameA(lpofn)
End Function

Function GetProcAddress_Handler(ByVal hMod as long, ByVal ProcOrOrd as Long) As Long
    If hMod = GetModuleHandle("comdlg32.dll") And cbool(ProcOrOrd and &hFFFF0000) Then
        If lstrcmp(ProcOrOrd, "GetOpenFileNameA") = 0 then
             GetProcAddress_Handler = Val(AddressOf GetOpenFileNameA_handler)
             Exit function
        end if
    End If
    GetProcAddress_Handler  = GetProcAddress(hMod, ProcOrOrd)
End Function


Если же важно покрыть случай, когда Add-in загружается после первой попытки использования Common Dialog-а, то лучше уж по сигнатуре искать структуру DYNALINKFUNC:
Код: Выделить всё
typedef struct
{
    LPCSTR  ProcNameOrOrd;
    FARPROC* pFuncPointer;
} DYNALINKFUNC;


Массивы подобных структур используются для отложенного импорта функций: делается вызов ф-ции EstablishDynalinks, и ей передаётся вот такой массив структур. Первое поле структуры содержит указатель на имя функции, а второе — указатель на указатель на функцию (EstablishDynalinks) по этому указателю записывает адрес, полученный от GetProcAddress, а весь прочий код пользуется им для вызовов.

Так вот — наша задача найти пару DWORD-ов, где первый DWORD указывает на строку «GetOpenFileNameA», а второй — на DWORD, численной равный адресу GetOpenFileNameA. Нашли — DWORD, на который указывает второе поле, переписываем, и перехват осуществлён. И всё это, повторяюсь, если уж нам так важно, чтобы даже загрузка Add-in'а после первичного обращения к Common Dialog тоже давала перехват.

The trick писал(а):то там придется отслеживать откуда вызов пришел - мало ли кто вызывал GetOpenFileNameA с произвольными аргументами.

Что в целом элементарно: GetMem4(VarPtr(arg1) - 4) сравниваем с границами модуля VBA6.EXE в АП процесса
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 15:34

К вопросу об отложенном импорте — он делается функцией EstablishDynalinks, которая имет такой псевдокод:
Код: Выделить всё
DWORD __stdcall EstablishDynalinks(
   LPCSTR lpszDllName,
   HMODULE * phmodLibrary,
   DWORD dwErrOnFail,
   BOOL fRememberErrOfFail,
   unsigned int cDynafuncs,
   DYNALINKFUNC * const Dynalinks)
{
   DWORD err;
   HMODULE hmod;
   
   if(*phmodLibrary != NULL) return ERROR_SUCCESS;
   
   hmod = LoadLibrary(lpszDllName);
   err = GetLastError();
   
   if(!hmod) goto error_handler;
   
   for(UINT i = 0; i < cDynafuncs; i++)
   {
      FARPROC FuncAddr;
      FuncAddr = GetProcAddress(hmod, Dynalinks[i].ProcNameOrOrd);
      *(Dynalinks[i].pFuncPointer) = FuncAddr;
      if(FuncAddr == NULL) goto error_handler;
   }
   
   *phmodLibrary = hmod;
   return ERROR_SUCCESS;
   
error_handler:
   if(fRememberErrOfFail) ErrorRemember(dwErrOnFail, lpszDllName);
   if(hmod) FreeLibrary(hmod);
   
   return dwErrOnFail;
}


Он «псевдо-», потому что в реальности там есть ещё синхронизация, которая отключена с помощью #if...#endif, когда Ruby компилируется для однопоточного выполнения (VB6.EXE), и включена для многопоточного (MSVBVM60.DLL).

Для загрузки подгрузки comdlg32.dll используется следующее:
Код: Выделить всё
static CHAR szComDlgDLL[] = "COMDLG32.DLL";
static CHAR szChooseFont[]           = "ChooseFontA";
static CHAR szCommDlgExtendedError[] = "ComDlgExtendedError";
static CHAR szGetSaveFileName[]      = "GetSaveFileNameA";
static CHAR szPrintDlg[]             = "PringDlgA";
static CHAR szChooseColor[]          = "ChooseColorA"
static CHAR szGetOpenFileName[]      = "GetOpenFileNameA";

static DYNALINKFUNC rgComDlgDynalinks[] = {
{
   {szChooseFont,           &ChooseFontAPI           },
   {szCommDlgExtendedError, &CommDlgExtendedErrorAPI },
   {szGetSaveFileName,      &GetSaveFileNameAPI      },
   {szPrintDlg,             &PrintDlgAPI             },
   {szChooseColor,          &ChooseColorAPI          },
   {szGetOpenFileName,      &GetOpenFileNameAPI      },
};


DWORD LoadComDlgDLL()
{
    return EstablishDynalinks(szComDlgDLL,
      &Rby_hinstComDlg,
      0x12A,
      TRUE,
      ARRAY_SIZE(rgComDlgDynalinks),
      rgComDlgDynalinks);
}


С такой же типовой начинкой есть ещё функции LoadMPRDLL(), LoadOleAutDLL(), LoadVerDLL(), LoadShellDLL(), LoadComCtlDLL(), LoadMSODLL().

А сама EstablishDynalinks вызывается также из:
  • _HrNewCRCRecordset — отложенный импорт VB5DB.DLL!DnaNewCRCRecordset.
  • ExtDeviceModeVB32 — отложенный импорт из WINSPOOL.DRV (ради OpenPrinterA, DocumentPropertiesA, ClosePrinter)
  • DeviceCapabilitiesVB32 — отложенный импорт из WINSPOOL.DRV (ради DeviceCapabilities)
  • DynLoadUrlMonLibrary — отложенный импорт urlmon.dll
  • ParentDlgProc — отложенный импорт OLEDLG.DLL (ради OleUIInsertObjectA и OleUIPasteSpecialA)
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 21.06.2019 (Пт) 19:34

Хакер писал(а):Будешь собирать все сигнатуры, включая всякие китайские билды VB6.EXE

Можно просто проверить и если сигнатура совпадает то с большой вероятностью на всех билдах она будет одинакова. Я сразу написал что это "грязный" метод, но т.к. новых билдов VB6.EXE больше не будет, то это допустимый способ.

The trick писал(а):то в целом элементарно: GetMem4(VarPtr(arg1) - 4) сравниваем с границами модуля VBA6.EXE в АП процесса

Ну так из VB6.exe тоже из нескольких мест вызывается GetOpenFileNameA (к примеру открытие изображений), придется еще анализировать дополнительно.
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 21.06.2019 (Пт) 20:00

Ух ты, как тут внезапно интересно и заковыристо!

Идея перехватить GetOpenFileName мне нравится - открывается перспектива заменить неказистые и тесные диалоги бейсика на нормальные.
Хакер писал(а):Что в целом элементарно: GetMem4(VarPtr(arg1) - 4) сравниваем с границами модуля VBA6.EXE в АП процесса
А если в отлаживаемом проекте будет GetOpenFileName, она, часом, тоже не перехватится?
Артур
 
   

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 21.06.2019 (Пт) 20:12

The trick писал(а):Ну как "грязное" решение можно занулить DWORD по адресу 0059F29C
Чтобы писать по этому адресу, нужно устанавливать какие-то разрешения?
Артур
 
   

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 21.06.2019 (Пт) 20:18

The trick писал(а): но т.к. новых билдов VB6.EXE больше не будет, то это допустимый способ.

Могут быть неофициальные пересборки :wink:

Но вопрос в другом: чем работа с сигнатурой и ковыряние в приватных полях объекта класса CFileRep (что против принципа инкапсуляции) лучше, чем работа в с документированным интерфейсом (в лице API-функции GetOpenFileName и структурой OPENFILENAME)?

The trick писал(а):Ну так из VB6.exe тоже из нескольких мест вызывается GetOpenFileNameA (к примеру открытие изображений), придется еще анализировать дополнительно.

Но автор не сказал, как он хочет поступать со всеми возможными диалогами, точнее с каждым конкретным в отдельности. В любом случае, дифференциировать разные по назначению диалоги гораздо проще по фильтру (там где *.vbp — там делаем подмену, остальные не трогаем), а не по адресу возврата.

arthur2 писал(а):А если в отлаживаемом проекте будет GetOpenFileName, она, часом, тоже не перехватится?

Перехват через правку ячейки IAT или правку указателя внутри VB6.EXE, в отличие от перехвата путём переписывания кода функции, затрагивает только интересующий нас модуль. На отлаживаемом проекте это не скажется.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 21.06.2019 (Пт) 21:11

arthur2 писал(а):
The trick писал(а):Ну как "грязное" решение можно занулить DWORD по адресу 0059F29C
Чтобы писать по этому адресу, нужно устанавливать какие-то разрешения?

Нет, он для записи.

Хакер писал(а):Могут быть неофициальные пересборки

Это радует! :D

Но вопрос в другом: чем работа с сигнатурой и ковыряние в приватных полях объекта класса CFileRep (что против принципа инкапсуляции) лучше, чем работа в с документированным интерфейсом (в лице API-функции GetOpenFileName и структурой OPENFILENAME)?

Не лучше, даже хуже в чем-то - просто альтернатива. Просто я говорю так как бы начал делать я (у меня мой билд тоже пропатченный в некоторых местах :D )

Но автор не сказал, как он хочет поступать со всеми возможными диалогами, точнее с каждым конкретным в отдельности. В любом случае, дифференциировать разные по назначению диалоги гораздо проще по фильтру (там где *.vbp — там делаем подмену, остальные не трогаем), а не по адресу возврата.

Согласен, и даже я и сам так планировал делать для VBPng, но отказался из-за усложнения кода.
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 01.07.2019 (Пн) 6:58

Хакер писал(а): у Add-in'а есть возможность перехватить GetProcAddress (правкой ячейки IAT — то есть в одну строчку) и подсунуть вместо GetOpenFileNameA свой адрес:
Код выглядит понятным... Вопрос, как найти эту ячейку? iat_cell_for_GPA

The trick писал(а):Ну как "грязное" решение можно занулить DWORD по адресу 0059F29C
В общем, занулить не получилось. В тестовом проекте, прямо из него, зануление иногда срабатывало, а иногда почему-то нет. Из адина - вообще не сработало ни разу. Пришлось вместо зануления писать реальный адрес данных публичной строки, в которую предварительно вписан нужный путь, конвертированный ФромУникод :) Это сработало. Интересно, почему не сработало зануление?
Артур
 
   

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 01.07.2019 (Пн) 9:46

arthur2 писал(а):В общем, занулить не получилось. В тестовом проекте, прямо из него, зануление иногда срабатывало, а иногда почему-то нет. Из адина - вообще не сработало ни разу. Пришлось вместо зануления писать реальный адрес данных публичной строки, в которую предварительно вписан нужный путь, конвертированный ФромУникод :) Это сработало. Интересно, почему не сработало зануление?

А что за тестовый проект? Путь там все время обновляется при открытии нового проекта, во-вторых, при занулении используется текущая папка - она обновлялась?
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 01.07.2019 (Пн) 10:08

The trick писал(а):А что за тестовый проект?
В том смысле, что не аддин. В модуле пишу публичную функцию, в ней меняю текущий диск, директорию и зануляю адрес. Затем просто прямо из Immediate запускаю эту функцию. Затем жму "открыть проект" и смотрю, сменилась ли папка. Иногда меняется (видимо, когда делаю это первый раз), иногда нет. Из аддина вообще не срабатывало ни разу. Подмена на реальный адрес вместо зануления работает всегда, так что, собственно, вопрос решен. Просто любопытно, почему не срабатывает зануление.
Артур
 
   

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 01.07.2019 (Пн) 11:06

arthur2 писал(а):в ней меняю текущий диск, директорию и зануляю адрес.

Каким образом? Что возвращает GetCurrentDirectory?
UA6527P

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 01.07.2019 (Пн) 11:26

arthur2 писал(а):Код выглядит понятным... Вопрос, как найти эту ячейку? iat_cell_for_GPA

Пройтись по таблице импорта и найти в ней дескриптор для «kernel32.dll», а дальше пройтись по цепочке lookup-ов и определить индекс лукапа, соответствующего GetProcAddress, а дальше, зная индекс, поправить значение соответствующей этому индексу ячейки IAT.

Посмотри мой кирпич «Вызов функции по указателю». В нём есть перехват DllFunctionCall через правку ячейки IAT.

Смотри код, начиная от комментария:
Код: Выделить всё
'
            ' В скомпилированном файле выполнить перехват всех вызовов функции
            ' DllFunctionCall из текущего модуля легко: достаточно подменить
            ' значение ячейки таблицы импорта текущего модуля.
            '


и вплоть до:
Код: Выделить всё
            '
            ' К этоу моменту адрес ячейки IAT известен: перезаписываем, и этим
            ' выполняем модуле-локальный перехват.
            '
           
            VirtualProtect lpIATEntry, 4, PAGE_EXECUTE_READWRITE, i
            PutMem4 lpIATEntry, AddressOf LocalResolver
            VirtualProtect lpIATEntry, 4, i, i
       
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 01.07.2019 (Пн) 11:33

The trick
стандартными ChDrive и ChDir. GetCurrentDirectory не проверял - вечером посмотрю. Но по меньшей мере иногда ChDrive и ChDir срабатывают правильно, потому что иногда зануление работает и путь меняется именно на тот, на который я менял.

Хакер
Спасибо! вечером попробую разобраться :)
Артур
 
   

The trick
Постоялец
Постоялец
 
Сообщения: 774
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Как сменить текущую директорию?

Сообщение The trick » 01.07.2019 (Пн) 11:39

arthur2 писал(а):стандартными ChDrive и ChDir

Нужно через SetCurrentDirectory. В VB6 есть такое понятие как текущая директория и текущий диск, в WinAPI нет, там только текущая директория. Текущие директории VB6 хранятся в переменных окружения.
UA6527P

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 01.07.2019 (Пн) 19:33

SetCurrentDirectory тоже пробовал с тем же эффектом - иногда срабатывает, а иногда (чаще) нет.
Артур
 
   

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

Re: Как сменить текущую директорию?

Сообщение Хакер » 01.07.2019 (Пн) 23:24

arthur2 писал(а):SetCurrentDirectory тоже пробовал с тем же эффектом - иногда срабатывает, а иногда (чаще) нет.

Ну и забудь про этот способ.

Вы не просто правите какую-то переменную в памяти стороннего процесса. Вы правите приватное поле экземпляра класса. Сама идея классов состоит в том, что можно внутренние данные объекта спрятать от внешнего мира, не разрешая внешнему миру прямое чтение и модификацию. Внешнему миру остаётся только набор публичных членов, в частности, публичных методов. Внешний мир вызывает публичные методы, и только они могут модифицировать приватные поля класса. Напрямую прикасаться к приватным полям объекта внешний мир возможности лишён.

И раз приватные поля могут быть изменены только кодом методов самого класса, сам код класса пишется с полной уверенностью программиста в том, что поле не может внезапно изменить своё значение (по велению третий сил и в обход вызова одного из методов), а также в том, что если какое-то значение было записано в приватное поле, оно прошло все необходимые проверки и другие сопутствующие действия (например, если поле хранит указатель на строку, то перед занулением память под строку будет освобождена ), и что если метод всегда наряду со значением одного поля меняет каким-то образом значение и какого-то другого поля (и что два поля всегда будут иметь взаимо-актуальные значения, и что если есть поля «указатель на строку» и «длина сроки», то не может быть такого, что первое внезапно станет указывать на другую строку, а второе останется со старым значением — длиной старой строки).

А вы собираетесь нарушить это ООП-овский принцип инкапсуляции и сокрытия.

Можно легко проверить с помощью OllyDbg: во всём коде VB6.EXE нет ни одного обращения к ячейке 0059F29C. Ни попытки прочитать DWORD по этому адресу, ни уж тем более — записать. Модификация и вообще доступ к этой ячейки (а это поле объекта) делается только через метода класса CFileRep.

Например через CFileRep::SetDirectory. Которая вызывает CFileRep::ReallocMemory, которая вызывает HeapAlloc/HeapRealloc.

Как минимум запись нуля по адресу 0059F29C напрямую (в обход методов класса) порождает утечку памяти. Как максимум — нужно разреверсить весь класс CFileRep, чтобы точно сказать, какие ещё нарушения целостности объекта происходят от такой прямой атаки по его данным. Навскидку могу сказать, третий DWORD в этом объекте инициализируется числом 1, когда сам объект инициализируется какой-то строкой. Когда вы зануляете второй DWORD, третий DWORD остаётся со значением 1. А первый DWORD содержит указатель на другой буфер, размер которого соответствует размеру буфера, указатель на который содержит второй DWORD (который вы зануляете). Когда вы зануляете второй DWORD, первый продолжает содержать указатель на буфер, который по размеру соответствует размеру старого буфера (указатель на который вы теряете и который становится «утёкшим» кусочком памяти). Непонятно, насколько для остального кода класса критично, когда из пары указателей на одинаковые буферы, один указатель меняется, а второй остаётся.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 02.07.2019 (Вт) 7:32

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

arthur2
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1688
Зарегистрирован: 23.01.2008 (Ср) 14:35

Re: Как сменить текущую директорию?

Сообщение arthur2 » 03.07.2019 (Ср) 20:51

Хакер
Итак, пробую перехватить диалог. В стандартном проекте GetProcAddress находится. Но в аддине-то перебирается импорт самого аддина, а там GetProcAddress нету :)

Если App.hInstance возвращается для самого аддина, как теперь считать смещения для бейсика?

Кстати, у тебя в коде опечатка:
Код: Выделить всё
                    ElseIf 0 = lstrcmpiA(vaModuleName, _
                                         Nm_RtlModuleName) = 0 Then
Артур
 
   

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

Re: Как сменить текущую директорию?

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

arthur2 писал(а):. Но в аддине-то перебирается импорт самого аддина, а там GetProcAddress нету

А зачем ты перебираешь импорт самого эддина?

Если App.hInstance возвращается для самого аддина, как теперь считать смещения для бейсика?

GetModuleHandle(NULL) даст адрес базы VB6.EXE. GetModuleHandle("VB6.EXE") использовать не стоит, потому что если exe-шник переименуют, всё перестанет работать. А его переименование предполагается да хотя бы моим консольным кирпичом (EasyConsole), да мало ли какими причинами ещё.

Кстати, у тебя в коде опечатка:

Нда уж, непорядок. Спасибо.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

След.

Вернуться в Visual Basic 1–6

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

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

    TopList