Всем привет! В общем мне нужно программно собрать сведения из куста SAM о всех учётных записях. Доступ ко вложенным ключам под админом я получил, но проблема в том, что ни одно из найденных в сети описаний структур F и V не совпадает с моим дампом - видимо это устаревшие прототипы для WinXP. Ключ "BootKey" для расшифровки хэшей NTLM я тоже собрал из ветки System\Lsa, и он совпадает с выхлопом mimikatz и прочих утилит. Мне нужны сведения как на этом скрине.
Нашёл я всё-таки доку по недокументированным структурам куста SAM. Если коротко, то по пути HKLM\SAM\SAM\Domains\Account\Users\<rid> имеем 2 параметра F и V. В первом лежит инфа о состоянии учётной записи, а во-втором 17 атрибутов с деталями типа SID, UserName, NTLM Hash, и многое другое. Я наложил найденную структуру на параметр(V), и сбоксил всю нарытую инфу в статики диалогового окна. В результате получился такой софт для сбора сведений обо всех учётных записях на лок.узле. Тестировал на Win7/10 и вроде всё работает правильно. Если кто найдёт ошибки - буду благодарен. В скрепке экзе для тестов, и сама дока pdf. 13 из 72 аверов на вирустотал шумят, но это нормально для софта с таким функционалом. Можно конечно снизить порог зашифровав строки и звать апи чз GetProcAddress(), но мне было лень заниматься этим. Запускать правой клавишей мыши от имени админа. Здесь лежит статья по теме. Спойлер: Source Код (ASM): format pe gui 6.0 entry start include 'win32ax.inc' include 'equates\reghive.inc' include 'encoding\win1251.inc' ;//------------------- .data ID_LV = 1000 ID_JD = 1001 ID_SK = 1002 ID_GB = 1003 ID_DT = 1004 ID_Key = 1005 ID_File = 1006 ID_Fsize = 1007 ID_Sam = 1008 ID_Win = 1009 ID_Stat = 1010 ID_Time = 1011 ID_Pass = 1012 ID_Bad = 1013 ID_Lcnt = 1014 ID_Bcnt = 1015 ID_NHash = 1016 ID_Sid = 1017 ID_Save = 1018 ID_Clear = 1019 RRF_RT_ANY = 0xffff RRF_RT_REG_BINARY = 0x0008 hLV dd 0 hModule dd 0 hDlg dd 0 hReg dd 0 hToken dd 0 hSamBackup dd 0 hSamUsers dd 0 hSamNames dd 0 hUserRid dd 0 index dd 0 osFlag dd 0 hMyBrush dd 0 ;// дескриптор кисти для фона Static lpClass dq 0,0,0,0,0 lpcClass dd 0 pcbBinary dd 16 pDataSize dd 0 ridBuff dd 0,0 pdwType dd 0 f_Buff rd 80 ;//<--- Буфер (fixed) align 16 sysKey db 'SYSTEM\CurrentControlSet\Control\Lsa\',0,0,0,0,0,0,0,0 subKey db 'JD',0,0,0,0 db 'Skew1',0 db 'GBG',0,0,0 db 'Data',0,0 subKeyName rb 16 align 16 usersPath db 'SAM\SAM\Domains\Account\Users\',0 users db 64 dup(0) align 16 namesPath db 'SAM\SAM\Domains\Account\Users\Names\',0 names db 64 dup(0) userOn db 'Активна',0 userOff db 'Отключена',0 ;//ShiftArray db 8,5,4,2,11,9,13,3,0,6,1,12,14,10,15,7 shiftArray db 16,10,8,4,22,18,26,6,0,12,2,24,28,20,30,14 hexKey dd 0,0,0,0,0,0,0,0 align 16 struct TOKEN_PRIVILEGES PrivilegeCount dd 1 ;// Счётчик добавляемых привилегий BckpLuid dq 0 ;// Место под Backup_LUID BckpPrivileges dd 2 ;// SE_PRIVILEGE_ENABLED ends tp TOKEN_PRIVILEGES lvi LV_ITEM lvc LV_COLUMN stm SYSTEMTIME nmlv NM_LISTVIEW colName0 db 'Учётная запись',0 colName1 db 'RID',0 align 16 buff rb 2048 ;//------------------- .code start: invoke IsUserAnAdmin or eax,eax jnz @f invoke MessageBox,0,<'Ошибка! Требуются права админа.',0>,0,0x30 invoke ExitProcess,1 ;// Включаем привилегию "Backup" для доступа к SAM @@: invoke GetCurrentProcess invoke OpenProcessToken,eax,0x28, hToken lea eax,[tp.BckpLuid] invoke LookupPrivilegeValue,0,<'SeBackupPrivilege',0>,eax invoke AdjustTokenPrivileges,[hToken],0,tp,0,0,0 ;// 1 = Ок! invoke CloseHandle,[hToken] invoke InitCommonControls invoke GetModuleHandle,0 mov [hModule],eax invoke DialogBoxParam, eax,100,0,DialogProc,0 invoke ExitProcess, 0 proc DialogProc hwnd, msg, wparam, lparam mov eax,[hwnd] mov [hDlg],eax cmp [msg],WM_INITDIALOG je @init cmp [msg],WM_COMMAND je @exit cmp [msg],WM_CLOSE je @close cmp [msg],WM_NOTIFY je @notify cmp [msg],WM_CTLCOLORSTATIC je @strgb jmp @next ;//*************************************************** ;//****** Обработчик "WM_CTLCOLORSTATIC" ************* ;//*************************************************** ;// wParam = контекст устройства HDC ;// lParam = дескриптор элемента управления @strgb: invoke GetDlgCtrlID,[lparam] mov ecx,17 mov ebx,1001 @@: push eax ebx ecx cmp eax,ebx je @f pop ecx ebx eax inc ebx loop @b jmp @next ;5d260e @@: invoke SetTextColor,[wparam],0x080848 ;// 00BBGGRR invoke SetBkMode,[wparam],TRANSPARENT ;// прозрачный фон invoke GetSysColorBrush,COLOR_BTNFACE ;// обязательно возвратить стд.кисть! ret ;//*************************************************** ;//****** Обработчик сообщения "WM_INITDIALOG" ******* ;//*************************************************** @init: invoke SetWindowText,[hwnd],<'SAM Hive Info v0.1. (Demo version)',0> ;//------ Версия Windows mov esi,[ fs:0x30] mov eax,[esi+0xA4] mov ebx,[esi+0xA8] movzx ecx,word[esi+0xAC] movzx edx,word[esi+0xAE] shr edx,8 mov [osFlag],eax cinvoke wsprintf,buff,<'Microsoft Windows %d.%d.%d - SP%d',0>,eax,ebx,ecx,edx invoke SetDlgItemText,[hwnd],ID_Win,buff ;//------ Отключить буттон "Сброс пароля" invoke GetDlgItem,[hwnd],ID_Clear ; invoke EnableWindow,eax,0 ;//------ Вставим иконку в окно invoke LoadIcon,[hModule],101 invoke SendMessage,[hwnd],WM_SETICON,ICON_BIG,eax ;//------ Получить дескриптор контрола ListView invoke GetDlgItem,[hwnd],ID_LV mov [hLV],eax ;//------ Установить для него расширенный стиль invoke SendMessage,eax,LVM_SETEXTENDEDLISTVIEWSTYLE,0,\ LVS_EX_FULLROWSELECT + LVS_EX_GRIDLINES ;//------ Вставить столбцы "LV_COLUMN" в список mov [lvc.mask],LVCF_TEXT + LVCF_WIDTH + LVCF_FMT mov [lvc.cx],140 mov [lvc.pszText],colName0 invoke SendMessage,[hLV], LVM_INSERTCOLUMN, 0, lvc mov [lvc.cx],75 mov [lvc.pszText],colName1 mov [lvc.fmt],LVCFMT_CENTER invoke SendMessage,[hLV], LVM_INSERTCOLUMN, 1, lvc ;//------ Читаем в цикле классы ..\LSA\JD-Skew1-GBG-Data mov ebx,lpClass mov esi,subKey mov edi,sysKey+37 mov ecx,4 @@: push ecx esi edi ebx ebx mov ecx,6 rep movsb mov [lpcClass],16 invoke RegOpenKeyEx,HKEY_LOCAL_MACHINE,sysKey,0,KEY_QUERY_VALUE,hReg pop ebx invoke RegQueryInfoKey,[hReg],ebx,lpcClass,0,0,0,0,0,0,0,0,0 invoke RegCloseKey,[hReg] pop ebx edi esi ecx add esi,6 add ebx,8 loop @b ;//------ Вывод имён классов в статики @@: mov eax,subKey mov esi,lpClass mov edi,subKeyName mov ecx,4 mov ebx,ID_JD @@: push eax ebx esi edi ecx mov ecx,8 rep movsb stdcall UpperCase,subKeyName,8 invoke SetDlgItemText,[hwnd],ebx,subKeyName pop ecx edi esi ebx eax add esi,8 add eax,6 inc ebx ;// ID_JD..SK\GB\DT loop @b ;//------ Формируем ключ "BootKey" из имён классов LSA mov esi,lpClass mov edi,buff mov ecx,16 mov edx,shiftArray @@: movzx ebx,byte[edx] mov ax,word[esi+ebx] stosw inc edx loop @b stdcall UpperCase,buff,32 invoke SetDlgItemText,[hwnd],ID_Key,buff ;//------ Строка в НЕХ-число для записи в файл invoke CryptStringToBinary,buff,32,4,\ ;//<-- CRYPT_STRING_HEX hexKey,pcbBinary,0,0 invoke _lcreat,<'BootKey.bin',0>,0 ;// Запись ключа в файл! push eax invoke _lwrite,eax,hexKey,16 pop eax invoke _lclose,eax invoke SetDlgItemText,[hwnd],ID_File, <'BootKey.bin',0> invoke SetDlgItemText,[hwnd],ID_Fsize,<'16 byte',0> ;//******************************************* ;//------ Пытаемся открыть куст SAM ;//******************************************* invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,\ ;//<------------- 0 = OK! <'SAM\SAM\Domains\Account\Users\Names',0>,0,0,\ REG_OPTION_BACKUP_RESTORE, KEY_READ,0,hSamNames,0 or eax,eax jz @f invoke MessageBox,0,<'Ошибка!',10,\ 'Не удалось получить доступ к разделу SAM.',0>,\ <'SAM Hive Info v0.1.',0>,0x10 jmp @close @@: invoke SetDlgItemText,[hwnd],ID_Sam,\ <'HKLM\SAM\SAM\Domains\Account\Users\',0> ;// Цикл заполнения ListView... @listViewRow: mov dword[pDataSize],64 invoke RegEnumKeyEx,[hSamNames],[index],buff,pDataSize,0,0,0,0 cmp eax,259 ;//<------ ERROR_NO_MORE_ITEMS jz @f mov eax,[index] mov [lvi.mask],LVIF_TEXT mov [lvi.pszText],buff mov [lvi.iItem],eax mov [lvi.lParam],eax mov [lvi.iSubItem],0 invoke SendMessage,[hLV],LVM_INSERTITEM,0,lvi stdcall ClearBuff,names,64 invoke lstrcat,namesPath,buff invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,namesPath,0,0,\ REG_OPTION_BACKUP_RESTORE, KEY_READ,0,hSamUsers,0 mov [pDataSize],8 mov [ridBuff],0 invoke RegGetValue,[hSamUsers],0,0,\ RRF_RT_ANY,pdwType,ridBuff,pDataSize cinvoke wsprintf,buff,<'%08X',0>,[pdwType] mov [lvi.mask],LVIF_TEXT mov [lvi.pszText], buff mov [lvi.iSubItem],1 invoke SendMessage,[hLV],LVM_SETITEM,0,lvi inc [index] jmp @listViewRow @@: invoke RegCloseKey,[hSamNames] invoke RegCloseKey,[hSamUsers] jmp @next ;//******************************************************** ;//****** Обработчик "WM_NOTIFY" (клик в строке ListView) ;//******************************************************** @notify: mov esi,[lparam] mov ebx,[esi+NMHDR.code] cmp ebx,NM_CLICK jne @exit mov ecx,[esi+NM_ITEMACTIVATE.iItem] cmp ecx,-1 je @exit mov [lvi.iItem],ecx mov [lvi.iSubItem],1 mov [lvi.pszText],buff mov [lvi.cchTextMax],16 invoke SendMessage,[hLV],LVM_GETITEMTEXT,ecx,lvi call ParseFVkey jmp @next ;//******************************************************** ;//****** Обработчики сообщений "WM_CLOSE/COMMAND" ******** ;//******************************************************** @exit: cmp [wparam],BN_CLICKED shl 16 + ID_Save jne @f invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,<'SAM',0>,0,0,\ REG_OPTION_BACKUP_RESTORE, KEY_READ,0,hSamBackup,0 invoke RegSaveKeyEx,[hSamBackup],<'BackupSAM.regf',0>,0,2 invoke RegCloseKey, [hSamBackup] invoke MessageBox,0,<'Раздел реестра успешно сохранён в файле "BackupSAM.regf"!',0>,\ <'SAM Hive Info v0.1',0>,0x40 jmp @next @@: cmp [wparam],BN_CLICKED shl 16 + ID_Clear jne @f invoke MessageBox,0,<'Функционал не реализован в данной версии!',0>,\ <'SAM Hive Info v0.1',0>,0x40 @@: cmp [wparam],BN_CLICKED shl 16 + IDCANCEL jne @next @close: invoke EndDialog,[hwnd], 0 @next: xor eax,eax @return: ret endp ;//============= ПРОЦЕДУРЫ ================ ;//------ Перевод строки в верхний рестр align 8 proc UpperCase Addr,Size mov edi,[Addr] mov ecx,[Size] @upper: cmp byte[edi],'a' jb @fuck cmp byte[edi],'f' ja @fuck and byte[edi],0xDF @fuck: inc edi loop @upper ret endp ;//------ Очищает буферы для сл.операций align 8 proc ClearBuff Offset,Size mov edi,[Offset] mov ecx,[Size] xor eax,eax rep stosb mov eax,[Offset] dec eax mov byte[eax],0 ret endp ;//------ Парсит ключи F и V учётных записей ;// На входе: в "buff" лежит строка RID выбранного юзера align 8 proc ParseFVkey pusha stdcall ClearBuff,users,64 invoke lstrcat,usersPath,buff invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,usersPath,0,0,\ REG_OPTION_BACKUP_RESTORE,KEY_READ,0,hUserRid,0 or eax,eax jz @f invoke MessageBox,0,<'Ошибка!',10,\ 'Не удалось открыть \Account\Users\RID*',0>,\ <'SAM Hive Info v0.1',0>,0x10 popa ret ;// Вывод инфы из ключа "F" (fixed) @@: stdcall ClearBuff,f_Buff,80 mov [pDataSize],80 invoke RegGetValue,[hUserRid],0,<'F',0>,RRF_RT_ANY,pdwType,f_Buff,pDataSize mov esi,f_Buff mov eax,[esi+SAM_F.ACB] ;//<----- состояние учётной записи mov ebx,userOff bt eax,0 ;// 0x01 = отключена jc @f mov ebx,userOn @@: invoke SetDlgItemText,[hDlg],ID_Stat,ebx mov esi,f_Buff lea eax,[esi+SAM_F.LastLogon] invoke FileTimeToSystemTime,eax,stm movzx eax,[stm.wDay] movzx ebx,[stm.wMonth] movzx ecx,[stm.wYear] cinvoke wsprintf,buff,<'%02d.%02d.%d',0>,eax,ebx,ecx invoke SetDlgItemText,[hDlg],ID_Time,buff mov esi,f_Buff lea eax,[esi+SAM_F.PassLastSet] invoke FileTimeToSystemTime,eax,stm movzx eax,[stm.wDay] movzx ebx,[stm.wMonth] movzx ecx,[stm.wYear] cinvoke wsprintf,buff,<'%02d.%02d.%d',0>,eax,ebx,ecx invoke SetDlgItemText,[hDlg],ID_Pass,buff mov esi,f_Buff lea eax,[esi+SAM_F.LastBadPass] invoke FileTimeToSystemTime,eax,stm movzx eax,[stm.wDay] movzx ebx,[stm.wMonth] movzx ecx,[stm.wYear] cinvoke wsprintf,buff,<'%02d.%02d.%d',0>,eax,ebx,ecx invoke SetDlgItemText,[hDlg],ID_Bad,buff mov esi,f_Buff movzx eax,[esi+SAM_F.LogonCount] cinvoke wsprintf,buff,<'%d',0>,eax invoke SetDlgItemText,[hDlg],ID_Lcnt,buff mov esi,f_Buff movzx eax,[esi+SAM_F.BadPassCount] cinvoke wsprintf,buff,<'%d',0>,eax invoke SetDlgItemText,[hDlg],ID_Bcnt,buff ;// Вывод инфы из ключа "V" (variable) stdcall ClearBuff,buff,2048 mov [pDataSize],2048 invoke RegGetValue,[hUserRid],0,<'V',0>,RRF_RT_ANY,pdwType,buff,pDataSize or eax,eax jz @f invoke MessageBox,0,<'Ошибка!',10,'Не удалось прочитать ключ(V)',0>,0,0x10 popa ret @@: invoke SetDlgItemText,[hDlg],ID_NHash,<'Не найден',0> invoke SetDlgItemText,[hDlg],ID_Sid,<'Учётная запись зарегистрированного пользователя',0> mov esi,buff push [esi+SAM_V.Comment.Offset] push [esi+SAM_V.Comment.Size] mov ebx,[esi+SAM_V.NTHash.Offset] add ebx,0xCC+4 add ebx,buff cmp [osFlag],10 jnz @win7 add ebx,4 @win7: mov eax,[esi+SAM_V.NTHash.Size] cmp eax,4 ja @ntOk jmp @comment @ntOk: mov eax,[ebx] mov ecx,[ebx+4] mov edx,[ebx+8] mov ebx,[ebx+12] bswap eax bswap ecx bswap edx bswap ebx cinvoke wsprintf, buff,<'%X%X%X%X',0>,eax,ecx,edx,ebx invoke SetDlgItemText,[hDlg],ID_NHash,buff @comment: pop ecx esi add esi,0xCC add esi,buff or ecx,ecx jz @end mov edi,buff+1024 shr ecx,1 @@: lodsw stosw loop @b mov dword[edi],0 invoke SetDlgItemTextW,[hDlg],ID_Sid,buff+1024 @end: invoke RegCloseKey,[hUserRid] popa ret endp ;//------------------ section '.idata' import data readable writeable library kernel32,'kernel32.dll',shell32,'shell32.dll',user32,'user32.dll',\ advapi32,'advapi32.dll',crypt32,'crypt32.dll',comctl32,'comctl32.dll',gdi32,'gdi32.dll' include 'api\user32.inc' include 'api\crypt32.inc' include 'api\shell32.inc' include 'api\kernel32.inc' include 'api\advapi32.inc' include 'api\comctl32.inc' include 'api\gdi32.inc' ;//------------------ section '.rsrc' data resource readable directory RT_DIALOG, dialogs,\ RT_GROUP_ICON, Icons,\ RT_ICON, my_icon resource dialogs, 100, LANG_ENGLISH + SUBLANG_DEFAULT, mainform resource Icons, 101, LANG_NEUTRAL, myicons resource my_icon, 102, LANG_NEUTRAL, myicon dialog mainform,'',0,0,400,240, DS_3DLOOK+WS_CAPTION+WS_SYSMENU+DS_CENTER,,,'Verdana',8 dialogitem 'Button',' Коды классов в ветке LSA ',\ -1,010,010,125,079, WS_VISIBLE+BS_GROUPBOX+BS_CENTER dialogitem 'Static',' Ключ JD', -1,015,028,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Ключ Skew1', -1,015,042,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Ключ GBG', -1,015,056,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Ключ Data', -1,015,070,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static','',ID_JD, 068,028,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_SK, 068,042,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_GB, 068,056,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_DT, 068,070,060,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Button',' Раздел реестра SAM - общая информация ',\ -1,150,010,240,079, WS_VISIBLE+BS_GROUPBOX+BS_CENTER dialogitem 'Static',' BootKey', -1,155,028,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Сохранён в', -1,155,042,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Доступна ветка',-1,155,056,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Версия ОС', -1,155,070,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static','',ID_Key, 215,028,167,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_File, 215,042,118,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Fsize, 340,042,041,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Sam, 215,056,167,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Win, 215,070,167,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Button',' Свойства учётной записи ',\ -1,150,098,240,110, WS_VISIBLE+BS_GROUPBOX+BS_CENTER dialogitem 'Static',' Состояние', -1,155,116,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Дата входа', -1,283,116,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Правка пароля',-1,155,131,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Неверный пасс',-1,270,131,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Всего входов в систему', -1,155,145,100,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Всего ошибок входа', -1,270,145,100,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Raw NTLM Hash',-1,155,160,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static',' Комментарий:', -1,155,174,060,010, WS_VISIBLE+WS_GROUP dialogitem 'Static','',ID_Stat, 215,116,050,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Time, 328,116,053,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Pass, 215,131,050,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Bad, 328,131,053,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Lcnt, 242,145,022,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Bcnt, 348,145,033,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_NHash,215,160,166,010, WS_VISIBLE+SS_CENTER+SS_SUNKEN dialogitem 'Static','',ID_Sid, 215,174,166,025, WS_VISIBLE+SS_CENTER+SS_EDITCONTROL dialogitem LISTVIEW_CLASS,'',ID_LV, 010,100,125,108, WS_VISIBLE+WS_BORDER +LVS_REPORT dialogitem 'BUTTON','Выход',IDCANCEL,275,218,115,013, WS_VISIBLE+BS_DEFPUSHBUTTON dialogitem 'BUTTON','Бэкап куста HKLM\SAM',\ ID_Save, 150,218,120,013, WS_VISIBLE+BS_PUSHBUTTON dialogitem 'BUTTON','Сбросить пароль',\ ID_Clear,010,218,125,013, WS_VISIBLE+BS_PUSHBUTTON enddialog icon myicons, myicon,'icon34.ico'
Marylin, извиняюсь что скажу не в тему,я смотрю на GUI интерфейс твоих прог,ты пользуешься каким нибудь GUI билдером что-ли ? просто в GUI билдере можно всякие кнопочки и т.д расставить по координатам,потом вручную эти координаты вбить в код на ASM
Хотя для этих целей есть WinAsmStudio, я все ресурсы описываю вручную, т.е. создал один например статик, и дальше просто копирую его меняя лишь координату Х или Y.