
I-FreeRDP iwukusetshenziswa komthombo ovulekile we-Remote Desktop Protocol (RDP), iphrothokholi ethuthukiswe yi-Microsoft yokulawula ikhompyutha ekude. Le phrojekthi isekela amapulatifomu amaningi, okuhlanganisa Windows, Linux, macOS ngisho ne-iOS ene AndroidLe phrojekthi ikhethwe njengeyokuqala ochungechungeni lwezihloko ezizinikele ekuhloleni amaklayenti e-RDP kusetshenziswa i-PVS-Studio static analyzer.
Umlando omncane
Le phrojekthi kwenzeke ngemuva kokuthi iMicrosoft ivule imininingwane yephrothokholi yayo ye-RDP. Ngaleso sikhathi, kwakukhona iklayenti le-rdesktop, ukuqaliswa kwalo kwakusekelwe emiphumeleni ye-Reverse Engineering.
Njengoba umthetho olandelwayo wawusetshenziswa, kwaba nzima kakhulu ukwengeza ukusebenza okusha ngenxa yesakhiwo sephrojekthi esasikhona ngaleso sikhathi. Izinguquko kuyo zibangele ukungqubuzana phakathi konjiniyela, okwaholela ekwakhiweni kwemfoloko ye-rdesktop - FreeRDP. Ukusatshalaliswa okwengeziwe komkhiqizo kukhawulelwe ilayisense ye-GPLv2, ngenxa yalokho kwathathwa isinqumo sokuwubuyisela ku-Apache License v2. Kodwa-ke, akubona bonke abavuma ukushintsha ilayisense yekhodi yabo, ngakho abathuthukisi banquma ukubhala kabusha iphrojekthi, okuholele ku-codebase yesimanje.
Ungafunda okwengeziwe ngomlando wephrojekthi kokuthunyelwe okusemthethweni kwebhulogi: βUmlando wephrojekthi ye-FreeRDPβ.
Kusetshenziswa njengethuluzi lokuhlonza amaphutha kanye nokuba sengozini okungaba khona kukhodi. Kuyi-analyzer yekhodi engaguquki ye-C, C++, C# kanye ne-Java, etholakala kumapulatifomu Windows, Linux ΠΈ macOS.
Lesi sihloko sinikeza kuphela lawo maphutha ayebonakala ethakazelisa kakhulu kimi.
Ukuvuza kwenkumbulo
Umsebenzi uphume ngaphandle kokukhulula isikhombi se-'cwd'. Ukuvuza kwenkumbulo kungenzeka. imvelo.c 84
DWORD GetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer)
{
char* cwd;
....
cwd = getcwd(NULL, 0);
....
if (lpBuffer == NULL)
{
free(cwd);
return 0;
}
if ((length + 1) > nBufferLength)
{
free(cwd);
return (DWORD) (length + 1);
}
memcpy(lpBuffer, cwd, length + 1);
return length;
....
}
Lesi siqeshana sithathwe ohlelweni olungaphansi lwe-winpr, olusebenzisa i-WINAPI wrapper ye-non-Windows izinhlelo, okungukuthi, iyi-analogue elula yewayini. Lapha ungabona ukuvuza: inkumbulo enikezwe umsebenzi tholacwd, ikhishwa kuphela lapho isingatha amacala akhethekile. Ukuze ulungise iphutha udinga ukungeza ikholi khulula ΠΏΠΎΡΠ»Π΅ memcpy.
Amalungu afanayo ngaphandle kwemingcele
Ukweqa kwe-array kungenzeka. Inani lenkomba ye-'event->EventHandlerCount' lingafinyelela ku-32. PubSub.c 117
#define MAX_EVENT_HANDLERS 32
struct _wEventType
{
....
int EventHandlerCount;
pEventHandler EventHandlers[MAX_EVENT_HANDLERS];
};
int PubSub_Subscribe(wPubSub* pubSub, const char* EventName,
pEventHandler EventHandler)
{
....
if (event->EventHandlerCount <= MAX_EVENT_HANDLERS)
{
event->EventHandlers[event->EventHandlerCount] = EventHandler;
event->EventHandlerCount++;
}
....
}
Lesi sibonelo sengeza i-elementi entsha ohlwini ngisho noma inani lezinto lifinyelele umkhawulo. Lapha kwanele ukufaka esikhundleni somsebenzisi <= on <, ukuze ungadluli imingcele yohlu.
Kutholwe elinye iphutha lalolu hlobo:
- Ukweqa kwe-V557 Array kungenzeka. Inani lenkomba ye-'iBitmapFormat' lingafinyelela ku-8. orders.c 2623
Ukuthayipha
Isiqephu 1
Inkulumo ethi '!pipe->In' ingamanga njalo. I-MessagePipe.c 63
wMessagePipe* MessagePipe_New()
{
....
pipe->In = MessageQueue_New(NULL);
if (!pipe->In)
goto error_in;
pipe->Out = MessageQueue_New(NULL);
if (!pipe->In) // <=
goto error_out;
....
}
Lapha sibona ukuthayipha okujwayelekile: isimo sesibili sihlola okuguquguqukayo okufanayo nesokuqala. Ngokunokwenzeka, iphutha livele ngenxa yokungaphumelelanga kokukopishwa kwekhodi.
Isiqephu 2
Kutholwe amabhulokhi amabili ombhalo ofanayo. Ibhulokhi yesibili iqala emgqeni 771. tsg.c 770
typedef struct _TSG_PACKET_VERSIONCAPS
{
....
UINT16 majorVersion;
UINT16 minorVersion;
....
} TSG_PACKET_VERSIONCAPS, *PTSG_PACKET_VERSIONCAPS;
static BOOL TsProxyCreateTunnelReadResponse(....)
{
....
PTSG_PACKET_VERSIONCAPS versionCaps = NULL;
....
/* MajorVersion (2 bytes) */
Stream_Read_UINT16(pdu->s, versionCaps->majorVersion);
/* MinorVersion (2 bytes) */
Stream_Read_UINT16(pdu->s, versionCaps->majorVersion);
....
}
Enye i-typo: ukuphawula kwekhodi kusho ukuthi intambo kufanele ifike inguqulo encane, nokho, ukufunda kwenzeka kube okuguquguqukayo okuqanjwe igama inguqulo enkulu. Nokho, angijwayelene nephrothokholi, ngakho lokhu kuwukuqagela nje.
Isiqephu 3
Kuyaxaka ukuthi indikimba yomsebenzi we-'trio_index_last' ilingana ngokugcwele nendikimba yomsebenzi we-'trio_index'. triostr.c 933
/**
Find first occurrence of a character in a string.
....
*/
TRIO_PUBLIC_STRING char *
trio_index
TRIO_ARGS2((string, character),
TRIO_CONST char *string,
int character)
{
assert(string);
return strchr(string, character);
}
/**
Find last occurrence of a character in a string.
....
*/
TRIO_PUBLIC_STRING char *
trio_index_last
TRIO_ARGS2((string, character),
TRIO_CONST char *string,
int character)
{
assert(string);
return strchr(string, character);
}
Ukwahlulela ngamazwana, umsebenzi inkomba_yezintathu ithola ukufana komlingisi wokuqala ochungechungeni uma trio_inkomba_kokugcina - into yokugcina. Kodwa imizimba yale misebenzi iyafana! Kungenzeka ukuthi lokhu kuyiphutha, futhi emsebenzini trio_inkomba_kokugcina isidingo sokusebenzisa strhrhr esikhundleni salokho strhr. Khona-ke ukuziphatha kuzolindeleka.
Isiqephu 4
Isikhombi 'sedatha' enkulumweni silingana ne-nullptr. Inani eliwumphumela wokusebenza kwe-arithmetic kulesi sikhombisi alinangqondo futhi akufanele lisetshenziswe. nsc_encode.c 124
static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context,
const BYTE* data,
UINT32 scanline)
{
....
if (!context || data || (scanline == 0))
return FALSE;
....
src = data + (context->height - 1 - y) * scanline;
....
}
Kubonakala sengathi u-opharetha wokuphika ugejwe lapha ngephutha ! Eduze idatha. Kuyamangaza ukuthi lokhu akuzange kubonwe.
Isiqephu 5
Ukusetshenziswa kokuthi 'uma (A) {...} okunye uma (A) {β¦}' iphethini itholiwe. Kukhona amathuba okuba khona kwephutha elinengqondo. Hlola imigqa: 213, 222. rdpei_common.c 213
BOOL rdpei_write_4byte_unsigned(wStream* s, UINT32 value)
{
BYTE byte;
if (value <= 0x3F)
{
....
}
else if (value <= 0x3FFF)
{
....
}
else if (value <= 0x3FFFFF)
{
byte = (value >> 16) & 0x3F;
Stream_Write_UINT8(s, byte | 0x80);
byte = (value >> 8) & 0xFF;
Stream_Write_UINT8(s, byte);
byte = (value & 0xFF);
Stream_Write_UINT8(s, byte);
}
else if (value <= 0x3FFFFF)
{
byte = (value >> 24) & 0x3F;
Stream_Write_UINT8(s, byte | 0xC0);
byte = (value >> 16) & 0xFF;
Stream_Write_UINT8(s, byte);
byte = (value >> 8) & 0xFF;
Stream_Write_UINT8(s, byte);
byte = (value & 0xFF);
Stream_Write_UINT8(s, byte);
}
....
}
Izimo ezimbili zokugcina ziyefana: ngokusobala othile ukhohlwe ukuzihlola ngemva kokukopisha. Kuyaphawuleka kukhodi ukuthi ingxenye yokugcina isebenza ngamanani angamabhayithi amane, ngakho-ke singacabanga ukuthi isimo sokugcina kufanele sibe inani <= 0x3FFFFFFFF.
Kutholwe elinye iphutha lalolu hlobo:
- V517 Ukusetshenziswa kwephethini ethi 'uma (A) {β¦} uma (A) {β¦}' iphethini itholakele. Kukhona amathuba okuba khona kwephutha elinengqondo. Hlola imigqa: 169, 173. file.c 169
Ukuqinisekiswa kwedatha yokufaka
Isiqephu 1
Inkulumo ethi 'strcat(target, source) != NULL' ihlale iyiqiniso. triostr.c 425
TRIO_PUBLIC_STRING int
trio_append
TRIO_ARGS2((target, source),
char *target,
TRIO_CONST char *source)
{
assert(target);
assert(source);
return (strcat(target, source) != NULL);
}
Ukuhlola umphumela womsebenzi kulesi sibonelo akulungile. Umsebenzi strcat ibuyisela isikhombisi enguqulweni yokugcina yeyunithi yezinhlamvu, i.e. ipharamitha yokuqala idlulile. Kulokhu kunjalo umgomo. Nokho, uma ilingana null, bese kuphuze kakhulu ukuyihlola, kusukela emsebenzini strcat izohoxiswa.
Isiqephu 2
Inkulumo ethi 'cache' ihlale iyiqiniso. glyph.c 730
typedef struct rdp_glyph_cache rdpGlyphCache;
struct rdp_glyph_cache
{
....
GLYPH_CACHE glyphCache[10];
....
};
void glyph_cache_free(rdpGlyphCache* glyphCache)
{
....
GLYPH_CACHE* cache = glyphCache->glyphCache;
if (cache)
{
....
}
....
}
Kulokhu okuguquguqukayo cache ikheli le-static array yabelwe glyphCache->glyphCache. Ngakho, hlola uma (inqolobane) ingashiywa.
Iphutha lokuphatha insiza
Insiza itholwe kusetshenziswa umsebenzi we-'CreateFileA' kodwa yakhululwa kusetshenziswa umsebenzi we-'fclose' ongahambelani. isitifiketi.c 447
BOOL certificate_data_replace(rdpCertificateStore* certificate_store,
rdpCertificateData* certificate_data)
{
HANDLE fp;
....
fp = CreateFileA(certificate_store->file, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
....
if (size < 1)
{
CloseHandle(fp);
return FALSE;
}
....
if (!data)
{
fclose(fp);
return FALSE;
}
....
}
Isichazi sefayela fp, idalwe ucingo lomsebenzi YakhaIfayela ivalwe ngephutha ngomsebenzi vala kusuka kumtapo wolwazi ojwayelekile, hhayi CloseHandle.
Izimo ezifanayo
Izinkulumo ezinemibandela zezitatimende 'uma' ezibekwe eduze kwesinye ziyefana. Hlola imigqa: 269, 283. ndr_structure.c 283
void NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg,
unsigned char* pMemory, PFORMAT_STRING pFormat)
{
....
if (conformant_array_description)
{
ULONG size;
unsigned char array_type;
array_type = conformant_array_description[0];
size = NdrComplexStructMemberSize(pStubMsg, pFormat);
WLog_ERR(TAG, "warning: NdrComplexStructBufferSize array_type: "
"0x%02X unimplemented", array_type);
NdrpComputeConformance(pStubMsg, pMemory + size,
conformant_array_description);
NdrpComputeVariance(pStubMsg, pMemory + size,
conformant_array_description);
MaxCount = pStubMsg->MaxCount;
ActualCount = pStubMsg->ActualCount;
Offset = pStubMsg->Offset;
}
if (conformant_array_description)
{
unsigned char array_type;
array_type = conformant_array_description[0];
pStubMsg->MaxCount = MaxCount;
pStubMsg->ActualCount = ActualCount;
pStubMsg->Offset = Offset;
WLog_ERR(TAG, "warning: NdrComplexStructBufferSize array_type: "
"0x%02X unimplemented", array_type);
}
....
}
Lesi sibonelo singase singabi yisiphazamisi. Nokho, yomibili le mibandela iqukethe imilayezo efanayo, okungenzeka ukuthi eyodwa yayo ingasuswa.
Ukuhlanza izinkomba ezingenalutho
I-null pointer idluliselwa kumsebenzi 'wamahhala'. Hlola impikiswano yokuqala. smartcard_pcsc.c 875
WINSCARDAPI LONG WINAPI PCSC_SCardListReadersW(
SCARDCONTEXT hContext,
LPCWSTR mszGroups,
LPWSTR mszReaders,
LPDWORD pcchReaders)
{
LPSTR mszGroupsA = NULL;
....
mszGroups = NULL; /* mszGroups is not supported by pcsc-lite */
if (mszGroups)
ConvertFromUnicode(CP_UTF8,0, mszGroups, -1,
(char**) &mszGroupsA, 0,
NULL, NULL);
status = PCSC_SCardListReaders_Internal(hContext, mszGroupsA,
(LPSTR) &mszReadersA,
pcchReaders);
if (status == SCARD_S_SUCCESS)
{
....
}
free(mszGroupsA);
....
}
Ukuze usebenze khulula ungadlulisa i-null pointer futhi umhlaziyi uyazi ngakho. Kodwa uma kutholwa isimo lapho i-pointer ihlale idluliswa ingenalutho, njengakulesi siqeshana, kuzokhishwa isixwayiso.
Isikhombi mszGroupsA ekuqaleni kuyalingana null futhi ayiqaliswa kwenye indawo. Okuwukuphela kwegatsha lekhodi lapho isikhombisi singaqalwa khona alifinyeleleki.
Bekuneminye imilayezo efana nalena:
- I-V575 Isikhombi esingenalutho sidluliselwa kumsebenzi 'okhululekile'. Hlola impikiswano yokuqala. ilayisensi.c 790
- I-V575 Isikhombi esingenalutho sidluliselwa kumsebenzi 'okhululekile'. Hlola impikiswano yokuqala. rdpsnd_alsa.c 575
Ngokunokwenzeka, okuguquguqukayo okunjalo okukhohliwe kuvela phakathi nenqubo yokuphinda kwenziwe futhi kungamane kususwe.
Ukuchichima okungenzeka
Ukuchichima okungenzeka. Cabangela ama-operands, hhayi umphumela. makecert.c 1087
// openssl/x509.h
ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj);
struct _MAKECERT_CONTEXT
{
....
int duration_years;
int duration_months;
};
typedef struct _MAKECERT_CONTEXT MAKECERT_CONTEXT;
int makecert_context_process(MAKECERT_CONTEXT* context, ....)
{
....
if (context->duration_months)
X509_gmtime_adj(after, (long)(60 * 60 * 24 * 31 *
context->duration_months));
else if (context->duration_years)
X509_gmtime_adj(after, (long)(60 * 60 * 24 * 365 *
context->duration_years));
....
}
Ukuletha umphumela ku eside akukona ukuvikela ukuchichima, njengoba ukubala ngokwako kwenzeka kusetshenziswa uhlobo Int.
Isikhombi siyehliswa ekuqaliseni
Isikhombi 'sokuqukethwe' sisetshenziswe ngaphambi kokuthi siqinisekiswe ngokumelene ne-nullptr. Hlola imigqa: 746, 748. gfx.c 746
static UINT gdi_SurfaceCommand(RdpgfxClientContext* context,
const RDPGFX_SURFACE_COMMAND* cmd)
{
....
rdpGdi* gdi = (rdpGdi*) context->custom;
if (!context || !cmd)
return ERROR_INVALID_PARAMETER;
....
}
Nasi isikhombi umongo ihoxiswa ngesikhathi sokuqalisa - ngaphambi kokuthi ihlolwe.
Amanye amaphutha alolu hlobo atholakele:
- I-V595 Isikhombi se-'ntlm' sisetshenziswe ngaphambi kokuthi siqinisekiswe ngokumelene ne-nullptr. Hlola imigqa: 236, 255. ntlm.c 236
- V595 Isikhombi 'sokuqukethwe' sisetshenziswe ngaphambi kokuthi siqinisekiswe ngokumelene ne-nullptr. Hlola imigqa: 1003, 1007. rfx.c 1003
- I-V595 Isikhombi se-'rdpei' sisetshenziswe ngaphambi kokuthi siqinisekiswe ngokumelene ne-nullptr. Hlola imigqa: 176, 180. rdpei_main.c 176
- I-V595 Isikhombi se-'gdi' sisetshenziswe ngaphambi kokuthi siqinisekiswe ngokumelene ne-nullptr. Hlola imigqa: 121, 123. xf_gfx.c 121
Isimo esingasho lutho
Isisho 'rdp->state >= CONNECTION_STATE_ACTIVE' sihlala siyiqiniso. uxhumano.c 1489
int rdp_server_transition_to_state(rdpRdp* rdp, int state)
{
....
switch (state)
{
....
case CONNECTION_STATE_ACTIVE:
rdp->state = CONNECTION_STATE_ACTIVE; // <=
....
if (rdp->state >= CONNECTION_STATE_ACTIVE) // <=
{
IFCALLRET(client->Activate, client->activated, client);
if (!client->activated)
return -1;
}
....
}
....
}
Kulula ukubona ukuthi umbandela wokuqala awunalutho ngenxa yenani elihambisanayo elinikezwe ngaphambili.
Ukuhlaziya iyunithi yezinhlamvu okungalungile
Ifomethi engalungile. Cabangela ukuhlola impikiswano yesithathu yangempela yomsebenzi we-'sscanf'. Isikhombi sohlobo lwe-int olungabhalisiwe silindelwe. ummeleli.c 220
Ingxenye yenkulumo enemibandela ihlale iyiqiniso: (rc >= 0). ummeleli.c 222
static BOOL check_no_proxy(....)
{
....
int sub;
int rc = sscanf(range, "%u", &sub);
if ((rc == 1) && (rc >= 0))
{
....
}
....
}
Umhlaziyi ngokushesha ukhipha izexwayiso ezi-2 zalesi siqeshana. Isicacisi %u ilindele ukuguquguquka kohlobo int engasayiniwe, kodwa iyaguquguquka sub inohlobo Int. Okulandelayo sibona isheke elisolisayo: isimo esingakwesokudla asinangqondo, kusukela ekuqaleni kukhona ukuqhathanisa neyodwa. Angazi ukuthi umbhali wale khodi ubesho ukuthini, kodwa kukhona okungahambi kahle lapha.
Amasheke angaphandle kwe-oda
Inkulumo ethi 'status == 0x00090314' ingamanga njalo. ntlm.c 299
BOOL ntlm_authenticate(rdpNtlm* ntlm, BOOL* pbContinueNeeded)
{
....
if (status != SEC_E_OK)
{
....
return FALSE;
}
if (status == SEC_I_COMPLETE_NEEDED) // <=
status = SEC_E_OK;
else if (status == SEC_I_COMPLETE_AND_CONTINUE) // <=
status = SEC_I_CONTINUE_NEEDED;
....
}
Izimo ezihloliwe zizohlala zingamanga, njengoba ukubulawa kuzofinyelela isimo sesibili kuphela uma isimo == SEC_E_OK. Ikhodi elungile ingase ibukeke kanje:
if (status == SEC_I_COMPLETE_NEEDED)
status = SEC_E_OK;
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
status = SEC_I_CONTINUE_NEEDED;
else if (status != SEC_E_OK)
{
....
return FALSE;
}
isiphetho
Ngakho-ke, ukuhlola iphrojekthi kwembula izinkinga eziningi, kodwa kuphela ingxenye ethakazelisa kakhulu yazo echazwe esihlokweni. Abathuthukisi bephrojekthi bangahlola iphrojekthi ngokwabo ngokucela ukhiye welayisensi yesikhashana kuwebhusayithi . Kwakukhona nemibono engamanga, umsebenzi ozosiza ukuthuthukisa i-analyzer. Kodwa-ke, ukuhlaziya okumile kubalulekile uma ungafuni ukuthuthukisa ikhwalithi yekhodi yakho kuphela, kodwa futhi unciphise isikhathi esichithwa ekutholeni amaphutha, futhi i-PVS-Studio ingasiza ngalokhu.
Uma ufuna ukwabelana ngalesi sihloko nezithameli ezikhuluma isiNgisi, sicela usebenzise isixhumanisi sokuhumusha: Sergey Larin.
Source: www.habr.com
