Обычным приемом при анализе стороннего приложения, является установка BP на API функциях и исследование вызывающего данные функции кода. Как контрприем, применяется эмуляция
API функций внутри тела приложения.
Например, при анализе триального приложения с привязкой ко времени, BP будет установлен на функции GetLocalTime(). Если проэмулировать ее вызов, то можно немного усложнить анализ кода приложения и/или уйти от различных утилит подменяющих дату, принцип которых построен на перехвате API . Ну как пример вот таких.
Например, при анализе триального приложения с привязкой ко времени, BP будет установлен на функции GetLocalTime(). Если проэмулировать ее вызов, то можно немного усложнить анализ кода приложения и/или уйти от различных утилит подменяющих дату, принцип которых построен на перехвате API . Ну как пример вот таких.
Вот так выглядит код эмуляции данной функции:
type KSYSTEM_TIME = packed record LowPart: DWORD; High1Time: Integer; High2Time: Integer; end; PKUSER_SHARED_DATA = ^KUSER_SHARED_DATA; KUSER_SHARED_DATA = packed record TickCountLow: ULONG; TickCountMultiplier: Integer; InterruptTime: KSYSTEM_TIME; SystemTime: KSYSTEM_TIME; TimeZoneBias: KSYSTEM_TIME; end; TIME_FIELDS = packed record Year, Month, Day, Hour, Minute, Second, Milliseconds, Weekday: Short; end; procedure GetLocalTime_Emul(var lpSystemTime: TSystemTime); const MM_SHARED_USER_DATA_VA = $7FFE0000; USER_SHARED_DATA: PKUSER_SHARED_DATA = PKUSER_SHARED_DATA(MM_SHARED_USER_DATA_VA); Magic10000: LARGE_INTEGER = (LowPart: $E219652C; HighPart: Integer($D1B71758)); SHIFT10000 = 13; Magic86400000: LARGE_INTEGER = (LowPart: $FA67B90E; HighPart: Integer($C6D750EB)); SHIFT86400000 = 26; WEEKDAY_OF_1601 = 1;
LeapYearDayToMonth: array [0..365] of Byte = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // January 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // February 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // March 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // April 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // May 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // June 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // July 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // August 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // September 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // October 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // November 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11); // December NormalYearDayToMonth: array [0..364] of Byte = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // January 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // February 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // March 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // April 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // May 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // June 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // July 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // August 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // September 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // October 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, // November 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11); // December LeapYearDaysPrecedingMonth: array[0..12] of Word = ( 0, // January 31, // February 31+29, // March 31+29+31, // April 31+29+31+30, // May 31+29+31+30+31, // June 31+29+31+30+31+30, // July 31+29+31+30+31+30+31, // August 31+29+31+30+31+30+31+31, // September 31+29+31+30+31+30+31+31+30, // October 31+29+31+30+31+30+31+31+30+31, // November 31+29+31+30+31+30+31+31+30+31+30, // December 31+29+31+30+31+30+31+31+30+31+30+31); NormalYearDaysPrecedingMonth: array[0..12] of Word = ( 0, // January 31, // February 31+28, // March 31+28+31, // April 31+28+31+30, // May 31+28+31+30+31, // June 31+28+31+30+31+30, // July 31+28+31+30+31+30+31, // August 31+28+31+30+31+30+31+31, // September 31+28+31+30+31+30+31+31+30, // October 31+28+31+30+31+30+31+31+30+31, // November 31+28+31+30+31+30+31+31+30+31+30, // December 31+28+31+30+31+30+31+31+30+31+30+31); var SystemTime, LocalTime, Bias, Temp: LARGE_INTEGER; TotalMilliseconds: LARGE_INTEGER; Years, Month, Days, Hours, Minutes, Seconds, Milliseconds: ULONG; NumberOf400s, NumberOf100s, NumberOf4s, ElapsedDays: ULONG; NumberOfLeapYears: ULONG; _IsLeapYear: Boolean; begin // эмуляция работы GetLocalTime SystemTime.HighPart := USER_SHARED_DATA^.SystemTime.High1Time; SystemTime.LowPart := USER_SHARED_DATA^.SystemTime.LowPart; Bias.HighPart := USER_SHARED_DATA^.TimeZoneBias.High1Time; Bias.LowPart := USER_SHARED_DATA^.TimeZoneBias.LowPart; LocalTime.QuadPart := SystemTime.QuadPart - Bias.QuadPart; // эмуляция вызова RtlTimeToTimeFields(&LocalTime,&TimeFields); // RtlTimeToTimeFields->TimeToDaysAndFraction // TotalMilliseconds = Convert100nsToMilliseconds( *(PLARGE_INTEGER)Time ); { #define Convert100nsToMilliseconds(LARGE_INTEGER) ( RtlExtendedMagicDivide( (LARGE_INTEGER), Magic10000, SHIFT10000 )) } asm push SHIFT10000 push Magic10000.HighPart push Magic10000.LowPart push LocalTime.HighPart push LocalTime.LowPart call @RtlExtendedMagicDivide jmp @end @RtlExtendedMagicDivide: push ebp mov ebp,esp sub esp,$0c push esi mov esi,[ebp+$0c] test esi,$80000000 jz @remd10 neg dword ptr [ebp+$0c] neg dword ptr [ebp+$08] sbb dword ptr [ebp+$0c],$00 @remd10: mov eax,[ebp+$10] mul dword ptr [ebp+$08] mov [ebp-$04],edx mov eax,[ebp+$10] mul dword ptr [ebp+$0c] mov [ebp-$08],eax mov [ebp-$0c],edx mov eax,[ebp+$14] mul dword ptr [ebp+$08] xor ecx,ecx add eax,[ebp-$04] adc ecx,$00 add eax,[ebp-$08] adc ecx,$00 mov [ebp-$04],edx mov eax,[ebp+$14] mul dword ptr [ebp+$0c] add eax,[ebp-$04] adc edx,$00 add eax,[ebp-$0c] adc edx,$00 add eax,ecx adc edx,$00 mov cl,[ebp+$18] @remd20: cmp cl,$1f jbe @remd30 sub cl,$1f shrd eax,edx,$1f shr edx,$1f jmp @remd20 @remd30: shrd eax,edx,cl shr edx,cl test esi,$80000000 jz @remd40 neg edx neg eax sbb edx,$00 @remd40: pop esi mov esp,ebp pop ebp ret $0014 @end: mov TotalMilliseconds.LowPart, eax mov TotalMilliseconds.HighPart, edx // RtlTimeToTimeFields->TimeToDaysAndFraction // Temp = ConvertMillisecondsToDays( TotalMilliseconds ); { #define ConvertMillisecondsToDays(LARGE_INTEGER) ( RtlExtendedMagicDivide( (LARGE_INTEGER), Magic86400000, SHIFT86400000 )) } push SHIFT86400000 push Magic86400000.HighPart push Magic86400000.LowPart push TotalMilliseconds.HighPart push TotalMilliseconds.LowPart call @RtlExtendedMagicDivide mov Temp.LowPart, eax mov Temp.HighPart, edx end; // RtlTimeToTimeFields->TimeToDaysAndFraction // *ElapsedDays = Temp.LowPart; Days := Temp.LowPart; // RtlTimeToTimeFields->TimeToDaysAndFraction // Temp.QuadPart = ConvertDaysToMilliseconds( *ElapsedDays ); { #define ConvertDaysToMilliseconds(DAYS) ( Int32x32To64( (DAYS), 86400000 )) } Temp.QuadPart := Days; Temp.QuadPart := Temp.QuadPart * 86400000; // RtlTimeToTimeFields->TimeToDaysAndFraction // Temp.QuadPart = TotalMilliseconds.QuadPart - Temp.QuadPart; Temp.QuadPart := TotalMilliseconds.QuadPart - Temp.QuadPart; // RtlTimeToTimeFields->TimeToDaysAndFraction // *Milliseconds = Temp.LowPart; Milliseconds := Temp.LowPart; // реализация TimeToDaysAndFraction закочена // TimeFields->Weekday = (CSHORT)((Days + WEEKDAY_OF_1601) % 7); lpSystemTime.wDayOfWeek := (Days + WEEKDAY_OF_1601) mod 7; // Years = ElapsedDaysToYears( Days ); // ElapsedDaysToYears - обычная математика ElapsedDays := Days; NumberOf400s := Days div 146097; Dec(ElapsedDays, NumberOf400s * 146097); NumberOf100s := (ElapsedDays * 100 + 75) div 3652425; Dec(ElapsedDays, NumberOf100s * 36524); NumberOf4s := ElapsedDays div 1461; Dec(ElapsedDays, NumberOf4s * 1461); Years := (NumberOf400s * 400) + (NumberOf100s * 100) + (NumberOf4s * 4) + (ElapsedDays * 100 + 75) div 36525; // Days = Days - ElapsedYearsToDays( Years ); { #define ElapsedYearsToDays(YEARS) ( ((YEARS) * 365) + NumberOfLeapYears(YEARS)) #define NumberOfLeapYears(YEARS) ( ((YEARS) / 4) - ((YEARS) / 100) + ((YEARS) / 400)) } NumberOfLeapYears := (Years div 4) - (Years div 100) + (Years div 400); Dec(Days, Years * 365 + NumberOfLeapYears); // if (IsLeapYear( Years + 1 )) { { #define IsLeapYear(YEARS) ( \ (((YEARS) % 400 == 0) || \ ((YEARS) % 100 != 0) && ((YEARS) % 4 == 0)) ? \ TRUE \ : \ FALSE \ ) } Inc(Years); _IsLeapYear := (Years mod 400 = 0) and (Years mod 100 <> 0) or (Years mod 4 = 0); Dec(Years); // и еще немного математики if _IsLeapYear then begin Month := LeapYearDayToMonth[Days]; Dec(Days, LeapYearDaysPrecedingMonth[Month]); end else begin Month := NormalYearDayToMonth[Days]; Dec(Days, NormalYearDaysPrecedingMonth[Month]); end; Seconds := Milliseconds div 1000; Milliseconds := Milliseconds mod 1000; Minutes := Seconds div 60; Seconds := Seconds mod 60; Hours := Minutes div 60; Minutes := Minutes mod 60; lpSystemTime.wYear := (Years + 1601); lpSystemTime.wMonth := (Month + 1); lpSystemTime.wDay := (Days + 1); lpSystemTime.wHour := Hours; lpSystemTime.wMinute := Minutes; lpSystemTime.wSecond := Seconds; lpSystemTime.wMilliseconds := Milliseconds; end;
Код совмести со всеми 32-битными версиями Delphi. Работает под всеми операционными системами начиная с W2K, до Windows 8 RTM включительно, как 32, так и 64 битные редакции.
Забрать полный код с коментариями и пример использования можно здесь.
Подсветка кода выполнена при помощи: http://tohtml.com/pascal/
запустил Вашу функцию эмуляции времени. Запустил свою программу, которая использует GetLocalTime. Время в моей программе не изменилось и я не понял- каким образом это использовать в защите... Извиняюсь я только начинающий, хотя и старый человек.
ОтветитьУдалитьЭмм, она не эмулирует время, а эмулирует саму функцию GetLocalTime, которую можно перехватить извне и изменить возвращаемое ей значение.
УдалитьТ.е. что результат вызова GetLocalTime, или вызов моего варианта кода в Вашем ПО будет идентичен.
Что за хуйня!? Александр ты что там микросхемы программируешь!? Код какой-то, я думал Pascal хорошо знаю, теперь я разочарован собой
ОтветитьУдалитьМы много чего программируем, как пики так и поноценную прошивку под ARM делаем. Но попрошу впредь без мата, т.к. в данном блоге посты нельзя редактировать - только удалять.
Удалить