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

Вы уже наверняка слышали о проблеме 2000 года, также известной как Y2K.

Для тех, кто не в курсе - раньше год часто выводился так:

printf("19%02d год",year);

Что в 2000 году выдало бы "19100 год". Проблема 2038 года несколько серьёзней.

19 января 2038 года время примет отрицательное значение из-за переполнения 32-битного числа, уходя в прошлое. Из-за этого, многие купленные программы лишатся лицензии.

Однако, мне удалось обойти это через параметр Sandboxie, InjectDll. Инъектор Sandboxie замечателен тем, что патчит все процессы браузера, в отличие от аналогичных программ, и не требует лончеров.

Следующий код работает как на x86, так и на x64.

#include <windows.h>
#include <stdlib.h>
#include <string.h>
/*сдвиг изначально ставится в 0, чтобы измерить размер*/
ULONGLONG shift=0;
/*эта функция используется только для замера*/
ULONGLONG ft2i(LPFILETIME d){
    ULONGLONG t=d->dwHighDateTime;
    t<<=32;
    t+=(unsigned)d->dwLowDateTime;
    return t;
}
/*Не совместимо с XP без обновлений
и более ранними
Можно убрать суффикс 64 для совместимости,
но тогда через какое-то время будет глюк*/
ULONGLONG gett(){
    ULONGLONG t=GetTickCount64();
    return t*10000+shift;
}
/*MS обещали удалить эту функцию.
Патчим, только если она есть*/
int WINAPI fake_NtQuerySystemTime(
PLARGE_INTEGER t){
    t->QuadPart=gett();
    return 0;
}
/*работает так же, как и NtQuerySystemTime
я проверил*/
void WINAPI fake_GetSystemTimeAsFileTime(
LPFILETIME d){
    ULONGLONG t=gett();
    d->dwLowDateTime=(int)t;
    d->dwHighDateTime=t>>32;
}
void WINAPI fake_GetSystemTime(
LPSYSTEMTIME t){
    FILETIME ft;
    fake_GetSystemTimeAsFileTime(&ft);
    FileTimeToSystemTime(&ft,t);
}
void*ptr_NtQuerySystemTime=fake_NtQuerySystemTime;
void*ptr_GetSystemTimeAsFileTime=fake_GetSystemTimeAsFileTime;
void*ptr_GetSystemTime=fake_GetSystemTime;
void _hook(char*d,LONGLONG*f){
    DWORD old;
    VirtualProtect(d,14,PAGE_EXECUTE_READWRITE,&old);
    /*на всякий случай сначала ставим int3*/
    d[0]=0xcc;
#ifdef _WIN64
    *(int*)(d+2)=0;
    *(LONGLONG*)(d+6)=*f;
#else
    *(int*)(d+2)=(int)f;
#endif
    d[1]=0x25;
    d[0]=0xff;
    /*MS очень не любят принимать NULL*/
    VirtualProtect(d,14,old,&old);
}
#define hook(d,f) _hook((void*)(d),(void*)(&f))
void patch(char const*s){
    void*d;
    HMODULE m=LoadLibraryA(s);
    if(!m)return;
    d=GetProcAddress(m,"NtQuerySystemTime");
    if(d)hook(d,ptr_NtQuerySystemTime);
    d=GetProcAddress(m,"GetSystemTimeAsFileTime");
    if(d)hook(d,ptr_GetSystemTimeAsFileTime);
    d=GetProcAddress(m,"GetSystemTimePreciseAsFileTime");
    if(d)hook(d,ptr_GetSystemTimeAsFileTime);
    d=GetProcAddress(m,"GetSystemTime");
    if(d)hook(d,ptr_GetSystemTime);
    d=GetProcAddress(m,"GetLocalTime");
    if(d)hook(d,ptr_GetSystemTime);
}
BOOL WINAPI DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved){
    char*a;
    FILETIME t;
    switch(fdwReason){ 
    case DLL_PROCESS_ATTACH:
        GetSystemTimeAsFileTime(&t);
        shift=ft2i(&t)-gett();
        a=getenv("Y38ADJ");/*единица - 4 года,
        таким образом, високосный год не сдвигается
        секундой в 100 лет можно пока пренебречь*/
        if(a)shift+=(atoll(a)*10000000)*126230400;
        patch("kernel32.dll");
        patch("kernelbase.dll");
        patch("ntdll.dll");
        break;
    }
    return TRUE;
}

Только последняя версия Sandboxie ещё работает с текущими браузерами. Я возьму для примера браузер Catsxp - он всё ещё работает с Windows 7. Ниже уже ничего не годится, к сожалению.

Пропущу создание самой песочницы, установку браузера...

В новых версиях Windows трудно открыть панель задач. Проще всего нажать Win-R и ввести sysdm.cpl.

Дополнительно - Переменные среды. Я создаю системную переменную Y38ADJ со значением 2.

Это переведёт время в патченых программах на 8 лет вперёд. Теперь я переведу системное время на 8 лет назад.

Теперь сам патч. В Sandboxie Опции-Редактировать Sandboxie.ini.

Нахожу строку [GlobalSettings].

Добавляю ниже ещё две строки, указывающие, куда я положил dll файлы. Теперь это выглядит так:

[GlobalSettings]
InjectDll=c:\adjtim\adjtim32.dll
InjectDll64=c:\adjtim\adjtim64.dll

И Catsxp работает, хотя система думает, что сейчас 2016 год. Это позволяет переводить время назад каждые 4 года, сохраняя функциональность протокола SSL.

Правда, не очень хорошо работает с DDOS защитой. И всё же Windows 7, 8 и 10 можут прожить ещё немного.

Ну как?

Комментарии (5)


  1. Einherjar
    22.06.2024 20:27
    +2

    Даже если закрыть глаза на довольно бессвязное изложение и хрестоматийный writeonly-код, возникает два вопроса:

    1 - Зачем это все если Windows использует 64 бита для времени в 100нс интервалах отсчитывая от 1601 года, и в 2038 никакого переполнения очевидно не произойдет?

    2 - Даже если бы такая проблема и была, то какой смысл решать проблему за 14 лет заранее на системах которые практически гарантированно до этого времени не доживут? В 2038 году никто же все равно не сможет пользоваться музейным железом для задач требующих работы в сети, а для оффлайн задач можно просто системную дату на прошлое поменять.


    1. Daimos
      22.06.2024 20:27

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


      1. Einherjar
        22.06.2024 20:27
        +1

        Тогда нехватает конкретики или примеров - что за софт и кому он будет нужен в 2038


      1. Serge78rus
        22.06.2024 20:27

        Это не какой-то "собственный формат", это стандартный формат времени Unix, возвращаемый стандартной C-шной функцией time(). И использовал его далеко не только "говнософт".


    1. dyadyaSerezha
      22.06.2024 20:27

      Предлагаю автору статьи решить проблему 100500-го в большой степени года, когда переполнится 64-битный счётчик. А то как жить-то?