Newer
Older
AMI-Aptio-BIOS-Reversed / MdeModulePkg / Universal / PCD / Dxe / PasswordCheck / PasswordCheck.md
@Ajax Dong Ajax Dong 2 days ago 6 KB Restructure the repo

PasswordCheck

Function Table

Address Name Description
StringLengthInChars
ModuleEntryPoint
DateTimeToEpochSeconds
GetMinPasswordLength
CheckTimeLockout
CheckPasswordHistory
SavePasswordWithHistory
GetRemainingLockoutDays
GetRemainingLockoutMinutes
GetRemainingVerifyCount
ManageVerifyCounters
DebugPrint
DebugAssertPrint
ReadUnaligned64
CompareGuid
CheckCmosReset
Global variables (from .data section at 0x1B60-0x1C40)
EFI_HANDLE gImageHandle = NULL; // 0x1BF8
0x1BE8 EFI_BOOT_SERVICES *gBS = NULL; // 0x1BF0
0x1C00 EFI_BOOT_SERVICES *BootServices_0 = NULL; // 0x1C18
0x1C28 EFI_RUNTIME_SERVICES *RuntimeServices_0 = NULL; // 0x1C20
0x1C10 VOID *gDebugProtocol = NULL; // 0x1C08
Protocol interface installed by this module (off_1BA0 / unk_1B90)
The actual interface data lives at 0x1BA0 in the binary
GUID used for password-related UEFI variables (unk_1B80)
GUID for the protocol installed by this module (unk_1B90)
GUID for HOB list lookup (unk_1B70)
GUID for debug protocol lookup (unk_1B60)
Days in each month (index 1-12)
static const UINT8 gDaysInMonth[13] = {
Forward declarations of internal helpers
Module entry point
Store global service table pointers
gImageHandle = (UINT64)ImageHandle;
Locate the HOB list
Cache local copies of the service tables
ProtocolHandle = 0;
Install the password check protocol
Status = BootServices->InstallProtocolInterface(
Check if the target year is a leap year
if (((Year & 3) == 0) &&
Accumulate seconds per full year from 2000 up to (but not including) Year
for (Y = BASE_YEAR; Y < Year; Y++) {
31536000 } else {
31622400 }
Accumulate seconds per completed month
for (M = 1; M < Month; M++) {
Add the day/hour/minute/second within the current month.
The formula matches the decompiled binary exactly:
TotalSeconds += (UINT64)(SECONDS_PER_HOUR * Hour - SECONDS_PER_HOUR)
Password policy enforcement functions
GUID components for the "Setup" variable (from decompilation)
1270213540 AttributeGuid[2] = 0x3E414D61; // 1044374945
return -((UINT64)(StringLengthInChars(Password) < MinLength) & PASSWORD_STATUS_NOT_FOUND_RET);
Read the Setup variable to get max lockout days
DataSize814 = VAR_DATA_SETUP_SIZE;
Determine max lockout days based on password type
MaxLockoutDays = (PasswordType == PASSWORD_TYPE_PAP)
Read the timestamp variable
DataSize8 = VAR_DATA_TIMESTAMP_SIZE;
Get current time via GetTime (RuntimeServices+24 = offset 0x18 = GetTime)
Status = gRT->GetTime(&CurrentTime, NULL);
If (now - saved) / 3600 < MaxLockoutDays, we are still in lockout
return -((UINT64)((EpochNow - EpochSaved) / SECONDS_PER_HOUR < MaxLockoutDays)
Read the Setup variable to get the history count
Read the password history variable
DataSize200 = VAR_DATA_HISTORY_SIZE;
Walk each 40-byte history entry, comparing the password
Compare the password string against this entry
PwScan = Password;
match found
If we broke early (EntryIndex < HistoryCount), password was reused.
return -((UINT64)(EntryIndex < HistoryCount) & PASSWORD_STATUS_NOT_FOUND_RET);
Empty password => delete the timestamp variable
if (*Password == 0) {
Read existing history
HistoryVarName = L"PapSaveHistory";
The decompiled code shifts history entries by 40 bytes (one entry)
so that the oldest entry is discarded and slot 0 is free.
if ((INT64)Status >= 0) {
Calculate password length (in characters)
Zero out the first entry slot, then copy the password into it
Write updated history back (SET_VARIABLE, Attributes=3 = NV+BS)
Result = RuntimeServices_0->RT->SetVariable(
Get current time and save as timestamp
EFI_TIME SaveTime;
Read save timestamp
Read Setup variable for max lockout days
Get current time
Read HaltStamp
Read Setup variable
Get lockout minutes from offset 0x1A in Setup variable
MaxLockoutMinutes = (UINT16 )&SetupBuf[0x1A];
Cooldown has elapsed delete HaltStamp
Read current verify count
Get max verify count
Reset mode: delete the verify counter variable
VerifyCntVarName = L"PapVerifyCnt";
Increment mode: read Setup variable
Read current count
Check against max
Under limit: save incremented count
Exceeded limit: record HaltStamp
Always reset counter to 0 after processing
Internal helper / library functions
probe before calling LocateProtocol. BootServices+0x18 = AllocatePages
result is <= 0x10 pages, it proceeds with LocateProtocol.
The exact pattern in the binary (from survey: no imports) suggests this
is a debug/production-build discriminator baked into the assert library.
The probe: gBS->AllocatePages(AllocateMaxAddress, EfiBootServicesData, 1, &Address)
then gBS->FreePages(Address). If the returned page count <= 0x10 (64KB)
the system is in a "debug" configuration and the protocol is located.
This pattern matches the EDK2 DebugLib initialization sequence.
Preserve bit 7 of CMOS address port, then select register 0x4B
CurrentAddr = IoRead8(CMOS_ADDRESS_PORT);
If value > 3 and non-zero, the system may be in a specific reset state.
If value == 0, read from a memory-mapped IO register to determine state.
if ((UINT8)RegValue > 3) {
Valid range check
if ((UINT8)(RegValue - 1) > 0xFD) {
Additional static data referenced by the module
The following data items reside in the binary at the specified offsets:

Generated by HR650X BIOS Decompilation Project