Disasm
Гость
|
|
« : 14-06-2006 03:25 » |
|
Как защитить память своего приложения от всяких гадостей типа ArtMoney? Или чтобы другие процессы получали ошибку при попытке ReadProcessMomory/WriteProcessMomory. Код защиты должен быть мой и распологаться или в самом защащаемом приложении или в приложении, которое запускает защищаемое.
ProcessGuard не предлагать :)
Спасибо.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 14-06-2006 08:05 » |
|
Disasm, очень просто блок защищаемых данных выделяешь через new и периодически выделяешь новое место, копируешь туда и удаляешь старые. Полезно несколько копий данных - и постоянно их синхронизировать
|
|
|
Записан
|
|
|
|
Disasm
Гость
|
|
« Ответ #2 : 14-06-2006 09:04 » |
|
Дело в том, что приложение (пусть это приложение A) не мое, изменять его структуру я не могу, я мой код является потоком в этом приложении. Как поставить на код и данные приложения такие права, чтобы никакое другое приложение на могло изменять память приложения A. Исходников приложения A у меня нет.
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #3 : 19-06-2006 07:19 » |
|
И при этом "другое приложение" выполнялось под именем администратора? Гм... Много миллиардов наносекунд назад я использовал VirtualProtectEx, и ArtMoney показывал что память моего приложения = 0 МБ. Это не совсем просто - но то что нужно...
|
|
|
Записан
|
while (8==8)
|
|
|
Disasm
Гость
|
|
« Ответ #4 : 19-06-2006 10:05 » |
|
И при этом "другое приложение" выполнялось под именем администратора? Гм... Много миллиардов наносекунд назад я использовал VirtualProtectEx, и ArtMoney показывал что память моего приложения = 0 МБ. Это не совсем просто - но то что нужно...
Можете рассказать как вы это делали: на какие регионы ставить защиту? Какие флаги защиты?
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #5 : 20-06-2006 01:05 » |
|
Сильно давно было, извини. Сейчас даже старых кодов нет (хана HDD)... Я тут подумал, а почему бы не создавать процесс с дескриптором безопасности, запрещающим PROCESS_VM_OPERATION для всех?
|
|
|
Записан
|
while (8==8)
|
|
|
Disasm
Гость
|
|
« Ответ #6 : 20-06-2006 04:57 » |
|
Можете рассказать как запускать процесс с этим дескриптором безопасности (а конкретно с флагом запрета PROCESS_VM_OPERATION)?
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #7 : 20-06-2006 05:43 » |
|
Тут тема, я скажу... Когда нибудь работал cо стандартным SecurityDescriptor? Если просто, он состоит из двух списков - SACL и DACL. Каждая строка такого списка называется ACE. Начнем с ACE. Это может быть разрешающая или запрещающая доступ строка, или строка аудита. Создадим union, т.к. это удобно. //--------------------------------------------------------------------------- typedef union STANDARD_ACE { ACE_HEADER aceHeader; ACCESS_ALLOWED_ACE aceAllowed; ACCESS_DENIED_ACE aceDenied; SYSTEM_AUDIT_ACE aceAudit; } *PSTANDARD_ACE;
#define ACESIDOFFSET (DWORD)(&((ACCESS_ALLOWED_ACE*) 0)->SidStart) #define ACESTRUCTSIZE (DWORD)(sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*) 0)->SidStart))
Дальше создадим класс: //*************************************************************************** //* CAce //*************************************************************************** class CAce { private: PSTANDARD_ACE FPAce; public: CAce(); CAce& New(DWORD dwType, DWORD dwFlags, DWORD dwMask, PSID psid);
CAce& NewAllowed(DWORD dwFlags, DWORD dwMask, PSID psid) {return New(ACCESS_ALLOWED_ACE_TYPE, dwFlags, dwMask, psid);};
CAce& NewDenied(DWORD dwFlags, DWORD dwMask, PSID psid) {return New(ACCESS_DENIED_ACE_TYPE, dwFlags, dwMask, psid);};
CAce& NewAudit(DWORD dwFlags, DWORD dwMask, PSID psid) {return New(SYSTEM_AUDIT_ACE_TYPE, dwFlags, dwMask, psid);};
~CAce(); operator PSTANDARD_ACE () {return FPAce;}; };
//*************************************************************************** //* CAce //*************************************************************************** CAce::CAce() { FPAce = NULL; } //--------------------------------------------------------------------------- CAce::~CAce() { if (FPAce) LocalFree(FPAce); } //--------------------------------------------------------------------------- CAce& CAce::New(DWORD dwType, DWORD dwFlags, DWORD dwMask, PSID psid) { if (FPAce) LocalFree(FPAce); FPAce = NewAce(dwType, dwFlags, dwMask, psid); return *this; } //--------------------------------------------------------------------------- PSTANDARD_ACE NewAce(DWORD dwType, DWORD dwFlags, DWORD dwMask, PSID psid) { PSTANDARD_ACE pace = NULL; PBYTE buf = NULL; try { DWORD dwSidSize = GetLengthSid(psid); buf = (PBYTE) LocalAlloc(LPTR, ACESTRUCTSIZE + dwSidSize); if (buf) { if (CopySid(dwSidSize, (PSID) (buf + ACESIDOFFSET), psid)) { pace = (PSTANDARD_ACE) buf; pace->aceHeader.AceSize = (USHORT) (ACESTRUCTSIZE + dwSidSize); pace->aceHeader.AceFlags = (BYTE) dwFlags; pace->aceHeader.AceType = (BYTE) dwType; pace->aceAllowed.Mask = dwMask; } } } catch(...) { } if (buf != (PBYTE) pace) LocalFree(buf); return pace; }
Теперь ACL #define ACLINITSIZE 0x0400 #define ACLSIZEDELTA 0x0040 class CAcl { private: PACL FPAcl; BOOL FCanonical; BOOL CreateAcl(DWORD dwSize = ACLINITSIZE);
BOOL TuningAclSize(PACL pAddAcl);
BOOL TuningAclSize(DWORD dwAddSize);
// Затирает старый BOOL RewriteAcl(PACL pSrcAcl);
// Добавляет BOOL AddAcl(PACL pSrcAcl);
// Возвращает индекс эквивалентного Ace int EqualAceIdx(PSTANDARD_ACE pAce);
public:
void clear();
public: CAcl(); ~CAcl() {clear();}; CAcl& operator += (PSTANDARD_ACE); PSTANDARD_ACE operator [] (DWORD idx); operator PACL () {return FPAcl;}; DWORD count(); }; //*************************************************************************** //* CAcl //*************************************************************************** CAcl::CAcl() { FPAcl = NULL; FCanonical = TRUE; } //--------------------------------------------------------------------------- void CAcl::clear() { if (FPAcl) { LocalFree(FPAcl); FPAcl = NULL; } } //--------------------------------------------------------------------------- BOOL CAcl::CreateAcl(DWORD dwSize) { clear(); if (dwSize < ACLINITSIZE) dwSize = ACLINITSIZE; FPAcl = (PACL) LocalAlloc(LPTR, dwSize); if (!FPAcl) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } else if (InitializeAcl(FPAcl, dwSize, ACL_REVISION)) return TRUE; else { LocalFree(FPAcl); FPAcl = NULL; return FALSE; } } //--------------------------------------------------------------------------- BOOL CAcl::TuningAclSize(DWORD dwAddSize) { BOOL fRes = FALSE; try { if (FPAcl == NULL) return CreateAcl(dwAddSize); ACL_SIZE_INFORMATION dstasi; if (GetAclInformation(FPAcl, &dstasi, sizeof(dstasi), AclSizeInformation)) { if (dstasi.AclBytesFree <= dwAddSize) { DWORD dwSize = dstasi.AclBytesInUse + dwAddSize; dwSize = ((dwSize / ACLSIZEDELTA) + 1) * ACLSIZEDELTA; PACL FTempAcl = (PACL) LocalAlloc(LPTR, dwSize); if (!FTempAcl) return FALSE; if (!InitializeAcl(FTempAcl, dwSize, ACL_REVISION)) { LocalFree(FTempAcl); return FALSE; } if (CopyAcl(FTempAcl, FPAcl)) { LocalFree(FPAcl); FPAcl = FTempAcl; fRes = TRUE; } else LocalFree(FTempAcl); } else fRes = TRUE; } } catch(...) { } return fRes; } //--------------------------------------------------------------------------- BOOL CAcl::TuningAclSize(PACL pAddAcl) { BOOL fRes = FALSE; try { ACL_SIZE_INFORMATION addasi; if (GetAclInformation(pAddAcl, &addasi, sizeof(addasi), AclSizeInformation)) { fRes = TuningAclSize(addasi.AclBytesInUse); } } catch(...) { } return fRes; } //--------------------------------------------------------------------------- BOOL CAcl::RewriteAcl(PACL pSrcAcl) { clear(); if (TuningAclSize(pSrcAcl)) return (CopyAcl(FPAcl, pSrcAcl)); else return FALSE; } //--------------------------------------------------------------------------- // Возвращает индекс эквивалентного Ace int CAcl::EqualAceIdx(PSTANDARD_ACE pAce) { return FindAceInAcl(FPAcl, pAce); } //--------------------------------------------------------------------------- DWORD CAcl::count() { DWORD dwRes = 0; try { if (FPAcl) { ACL_SIZE_INFORMATION asi; if (GetAclInformation(FPAcl, &asi, sizeof(asi), AclSizeInformation)) dwRes = asi.AceCount; } } catch(...) {} return dwRes; }
//--------------------------------------------------------------------------- PSTANDARD_ACE CAcl::operator [] (DWORD idx) { PSTANDARD_ACE pRes = NULL; try { PACE_HEADER pAce; if (GetAce(FPAcl, idx, (PVOID*) &pAce)) pRes = (PSTANDARD_ACE) pAce; } catch(...) {} return pRes; } //--------------------------------------------------------------------------- CAcl& CAcl::operator +=(PSTANDARD_ACE pAce) { if (pAce && TuningAclSize(pAce->aceHeader.AceSize)) { DWORD idx = EqualAceIdx(pAce); //MAXDWORD; // В конец ACL switch (idx) { case MAXDWORD: if (FCanonical) idx = GetCanonicalIndex(FPAcl, pAce); AddAce(FPAcl, ACL_REVISION, idx, (PVOID) pAce, pAce->aceHeader.AceSize); break; default: if (FCanonical) (*this)[idx]->aceAllowed.Mask = pAce->aceAllowed.Mask; } } return *this; } //--------------------------------------------------------------------------- // Добавляет BOOL CAcl::AddAcl(PACL pSrcAcl) { BOOL fRes = FALSE; try { if (TuningAclSize(pSrcAcl)) { ACL_SIZE_INFORMATION srcasi; if (GetAclInformation(pSrcAcl, &srcasi, sizeof(srcasi), AclSizeInformation)) { PACE_HEADER pAce; for (DWORD idx = 0; idx < srcasi.AceCount; idx++) { if (GetAce(pSrcAcl, idx, (PVOID*) &pAce)) { *this += (PSTANDARD_ACE) pAce; } else return FALSE; } fRes = TRUE; } } } catch(...){} return fRes; }
//--------------------------------------------------------------------------- DWORD CalculateAclSize(PACL pOldAcl, PSID* ppSidArray, DWORD dwNumSids, PSTANDARD_ACE* ppAces, DWORD dwNumAces) { DWORD res = 0; BOOL fOk = TRUE; try { if (pOldAcl) { ACL_SIZE_INFORMATION asi; fOk = GetAclInformation(pOldAcl, &asi, sizeof(asi), AclSizeInformation); if (fOk) res = asi.AclBytesInUse; } if (fOk && ppSidArray) { while (dwNumSids--) { fOk = IsValidSid(ppSidArray[dwNumSids]); if (fOk) { res += GetLengthSid(ppSidArray[dwNumSids]); res += sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*) 0)->SidStart); } else break; } } if (fOk && ppAces) { while (dwNumAces--) { res += ppAces[dwNumAces]->aceHeader.AceSize; } } } catch(...) { fOk = FALSE;} if (fOk) return res; else return 0; } //--------------------------------------------------------------------------- BOOL IsEqualAce(PSTANDARD_ACE pAce1, PSTANDARD_ACE pAce2) { BOOL fRes = FALSE; try { if (pAce1->aceHeader.AceType != pAce2->aceHeader.AceType) return FALSE; PBYTE pbAce1 = (PBYTE) pAce1; PBYTE pbAce2 = (PBYTE) pAce2; DWORD dwAceStructSize = ACESTRUCTSIZE; fRes = TRUE; // Жираф большой.... [1] стр.381 while (dwAceStructSize--) fRes = (fRes && (pbAce1[dwAceStructSize] == pbAce2[dwAceStructSize])); fRes = fRes && EqualSid((PSID)(pbAce1 + ACESIDOFFSET), (PSID)(pbAce2 + ACESIDOFFSET)); } catch(...) { } return fRes; } //--------------------------------------------------------------------------- int FindAceInAcl(PACL pAcl, PSTANDARD_ACE pAce) { int idx = -1; try { ACL_SIZE_INFORMATION asi; if (GetAclInformation(pAcl, &asi, sizeof(asi), AclSizeInformation)) { PSTANDARD_ACE pAce2; while (asi.AceCount--) { if (!GetAce(pAcl, asi.AceCount, (PVOID*) &pAce2)) break; if (IsEqualAce(pAce, pAce2)) { idx = (int) asi.AceCount; break; } } } } catch(...) { } return (idx); } //--------------------------------------------------------------------------- // Возвращает положенный по каноническом стандарту индекс Ace в DACL DWORD GetCanonicalIndex(PACL pDacl, PSTANDARD_ACE pNewAce) { DWORD idx = - 1; try { BYTE dwOrderFilterType [] = {ACCESS_DENIED_ACE_TYPE, ACCESS_DENIED_OBJECT_ACE_TYPE, ACCESS_ALLOWED_ACE_TYPE, ACCESS_ALLOWED_OBJECT_ACE_TYPE}; DWORD dwNewAceGroup = 0;
for (dwNewAceGroup; dwNewAceGroup < 4; dwNewAceGroup++) { if (pNewAce->aceHeader.AceType == dwOrderFilterType[dwNewAceGroup]) break; } // Если недопустимый тип нового Ace if (dwNewAceGroup == 4) return idx; // Если унаследованный то идет последним if ((pNewAce->aceHeader.AceFlags & INHERITED_ACE) != 0) dwNewAceGroup += 4; ACL_SIZE_INFORMATION asi; if (GetAclInformation(pDacl, &asi, sizeof(asi), AclSizeInformation)) { PACE_HEADER pAce; idx = 0; for (idx; idx < asi.AceCount; idx++) { if (GetAce(pDacl, idx, (PVOID*) &pAce)) { DWORD dwAceGroup = 0; for (dwAceGroup; dwAceGroup < 4; dwAceGroup++) { if (pAce->AceType == dwOrderFilterType[dwAceGroup]) break; } if (dwAceGroup == 4) { idx = - 1; return idx; // недопустимый ACE в DACL } // Если унаследованный то внесем поправку if ((pAce->AceFlags & INHERITED_ACE) != 0) dwAceGroup += 4; if (dwAceGroup >= dwNewAceGroup) break; } } // for idx } } catch(...) { } return idx; } //--------------------------------------------------------------------------- // Копирует ACL BOOL CopyAcl(PACL pDestAcl, PACL pSrcAcl) { BOOL fRes = FALSE; try { ACL_SIZE_INFORMATION asi; if (GetAclInformation(pSrcAcl, &asi, sizeof(asi), AclSizeInformation)) { PACE_HEADER pAce; for (DWORD idx = 0; idx < asi.AceCount; idx++) { if (!GetAce(pSrcAcl, idx, (PVOID*) &pAce)) return FALSE; if (!AddAce(pDestAcl, ACL_REVISION, MAXDWORD, (PVOID*) pAce, pAce->AceSize)) return FALSE; } } fRes = TRUE; } catch(...) { } return (fRes); }
Ну и в итоге используем: FObjHandle - Хэндл защищаемого процесса, открытого OpenProcess( PROCESS_ALL_ACCESS) pDacl - PACL ( см. CAcl.operator PACL) SetSecurityInfo( FObjHandle, FObjType, DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, NULL, NULL, pDacl, NULL); Удачи. Попробуй разобраться...
|
|
|
Записан
|
while (8==8)
|
|
|
Disasm
Гость
|
|
« Ответ #8 : 22-06-2006 10:57 » |
|
Разобрался. Но это система управления дескрипторами, и к тому же я не знаю чем их заполнять. Как создать подходящий SID (если требуется защита всей или некоторой области памяти своего процесса от воздействия других процессов)? Насколько я понял, что мой список ACL должен состоять из одной ACE (ACCESS_DENIED_ACE). Кроме того я не знаю какое должно быть значение параметра AccessMask для API функции BOOL AddAccessDeniedAce( PACL pAcl, // pointer to access-control list DWORD dwAceRevision, // ACL revision level DWORD AccessMask, // access mask PSID pSid // pointer to security identifier );
Помогите, пожалуйста!
|
|
|
Записан
|
|
|
|
sss
Специалист
Offline
|
|
« Ответ #9 : 23-06-2006 01:46 » |
|
1) Защита на основе списков доступа не позволит защищать области. Только объект процесса, и соответственно все его ресурсы, относительно учетных записей. Вот пример создания //--------------------------------------------------------------------------- PSID SECHLPAPI BuildAdministratorsSid() { SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY; //SECURITY_WORLD_SID_AUTHORITY PSID pRes = NULL; BOOL fRes = AllocateAndInitializeSid(&auth, 2, 32, 544, 0, 0, 0, 0, 0, 0, &pRes); return (fRes ? pRes : NULL); } //--------------------------------------------------------------------------- PSID SECHLPAPI BuildUsersSid() { SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY; //SECURITY_WORLD_SID_AUTHORITY PSID pRes = NULL; BOOL fRes = AllocateAndInitializeSid(&auth, 2, 32, 545, 0, 0, 0, 0, 0, 0, &pRes); return (fRes ? pRes : NULL); } //--------------------------------------------------------------------------- PSID SECHLPAPI NameToPSid(TCHAR* Name, PStr pDomain, LPDWORD pSidSize, PSID_NAME_USE peUse) { if (Name && pDomain) { BOOL fOk = FALSE; SID_NAME_USE pUse; DWORD dwDomainLen = 30; DWORD dwSidLen = 0; PSID psid = NULL; pDomain->SetLength(dwDomainLen, FALSE); fOk = LookupAccountName(NULL, Name, psid,&dwSidLen, (TCHAR*) pDomain->Buffer(), &dwDomainLen, &pUse); if (!fOk && (dwSidLen > 0 || dwDomainLen > 30)) { psid = LocalAlloc(LPTR, dwSidLen); pDomain->SetLength(dwDomainLen, FALSE); fOk = LookupAccountName(NULL, Name, psid, &dwSidLen, (TCHAR*) pDomain->Buffer(), &dwDomainLen, &pUse); if (!fOk && psid) { LocalFree(psid); psid = NULL; } } if (fOk) { if (peUse) *peUse = pUse; if (pSidSize) *pSidSize = dwSidLen; } return psid; } else { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } }
2) Думаю, что одной запрещающей ACE ты не обойдешся. Лучше прочитать список дескриптора процесса и добавить запрещающий ACE вверх. И интересно, какую информацию об памяти будет показывать TaskManager. 3) Для запрещения операций XxxProcessMemory. Sid = Everyony (А лучше, того кто запустил...) AccessMask = PROCESS_VM_OPERATION 4) Предполагаю, есть еще подводный камень. Владелец объектом. Если владельцем объекта будет пользователь, запустивший процесс (что скорее всего), доступ к объекту осуществляется в обход проверок списка доступа. Т.е. необходимо будет поменять владельца. Для смены владельца необходима привилегия SeTakeOwnership, которая неотемлимо (!) присутствует для учетной записи Администратор. Хоть тресни. Отсюда следует, что сопротивление программе, запущенной под этой учетной записью, и умеющей работать с дескриптором безопасности невозможно. Но, неотемлимость привилегии не распространяется (блин не помню точно ли! посмотрю допишу) на учетные записи, входящую в группу Администраторы. Дальше делай выводы. Вот код, как сменить владельца в дескрипторе объекта. Вначале добавляем себе право менять владельца, меняем, возвращаем как было. SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION | PROTECTED_SACL_SECURITY_INFORMATION; BOOL fRes = FALSE; DWORD dwOldState_Restore = MAXDWORD; DWORD dwOldState_TakeOwner = MAXDWORD;
try { SetProcessPrivilege(NULL, SE_RESTORE_NAME, TRUE, &dwOldState_Restore); SetProcessPrivilege(NULL, SE_TAKE_OWNERSHIP_NAME, TRUE, &dwOldState_TakeOwner);
switch (FNameUse) { case FALSE: FError = SetSecurityInfo(FObjHandle, FObjType, si, pOwnerSid, pOwnerSid, NULL, NULL); break; case TRUE: FError = SetNamedSecurityInfo(FObjName, FObjType, si, pOwnerSid, pOwnerSid, NULL, NULL); break; }
if (dwOldState_Restore == 0) SetProcessPrivilege(NULL, SE_RESTORE_NAME, FALSE); if (dwOldState_TakeOwner == 0) SetProcessPrivilege(NULL, SE_TAKE_OWNERSHIP_NAME, FALSE);
if (FError != ERROR_SUCCESS) SetLastError(FError); else { fRes = TRUE; GetDescriptor(); } } catch(...) { } return fRes;
//--------------------------------------------------------------------------- // Разрешает/запрещает привилегию процесса BOOL SetProcessPrivilege(HANDLE hProcess, TCHAR* PrivilegeName, BOOL fEnable, LPDWORD pPrevAttributes) { BOOL fRes = FALSE; HANDLE hProc = NULL; HANDLE hToken = NULL; TOKEN_PRIVILEGES priv; LUID luid; if (hProcess) hProc = hProcess; else hProc = OpenProcess(PROCESS_TOKEN_RIGHTS, FALSE, GetCurrentProcessId()); if (hProc && OpenProcessToken(hProc, TOKEN_ALL_ACCESS, &hToken)) { priv.PrivilegeCount = 1; if (LookupPrivilegeValue(NULL, PrivilegeName, &luid)) { DWORD dwLength = sizeof(priv); priv.Privileges[0].Luid = luid; priv.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0; fRes= AdjustTokenPrivileges(hToken, FALSE, &priv, dwLength, &priv, &dwLength); if (pPrevAttributes) *pPrevAttributes = priv.Privileges[0].Attributes; } CloseHandle(hToken); } if (hProcess == NULL) if (hProc) CloseHandle(hProc); return fRes; }
P.S.: Если мне кто-нибудь задаст вопрос об разрешениях для объектов Active Directory я застрелюсь.
|
|
|
Записан
|
while (8==8)
|
|
|
|