Здравствуйте, господа. Милостиво прошу вас извинить меня, если я позволил себе допустить какие-либо недочёты, это моя первая проба пера.
Вы уже наверняка слышали о проблеме 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 можут прожить ещё немного.
Ну как?
Einherjar
Даже если закрыть глаза на довольно бессвязное изложение и хрестоматийный writeonly-код, возникает два вопроса:
1 - Зачем это все если Windows использует 64 бита для времени в 100нс интервалах отсчитывая от 1601 года, и в 2038 никакого переполнения очевидно не произойдет?
2 - Даже если бы такая проблема и была, то какой смысл решать проблему за 14 лет заранее на системах которые практически гарантированно до этого времени не доживут? В 2038 году никто же все равно не сможет пользоваться музейным железом для задач требующих работы в сети, а для оффлайн задач можно просто системную дату на прошлое поменять.
Daimos
Это видимо для говнософта, который зачем-то использует собственный формат хранения даты.
Einherjar
Тогда нехватает конкретики или примеров - что за софт и кому он будет нужен в 2038
Serge78rus
Это не какой-то "собственный формат", это стандартный формат времени Unix, возвращаемый стандартной C-шной функцией time(). И использовал его далеко не только "говнософт".
dyadyaSerezha
Предлагаю автору статьи решить проблему 100500-го в большой степени года, когда переполнится 64-битный счётчик. А то как жить-то?