
ááªá áá²á (FreeRDP) ášá©á
áŽáµáá¶á áá®á¶á®á (RDP) áááµ ááá áµáá á« á²áá áá
á á áááá®á¶ááµ ášá°ááá ášáááµ á®áááá°á áá¥á¥á áá®á¶á®á ááᢠáá®ááá± á áá«á³ ááµášá®áœá áá°áááᣠášá¥ááá
á ááµá¥ Windows, Linux, macOS á¥á iOS á¥áá³á áš áá Androidáá
áá®áááµ áš PVS-áµá±á²á® áµá³á²á á ááááá á áá áá áš RDP á°áá ááœá áááá°áœ ášá°ááááµ á°ášá³á³á áá£á¥áᜠááµá¥ ášááááªá«á áá á°ááá§áá¢
áµáᜠá³áªá
áá®ááá± áááá®á¶ááµ ášá£áá€áµááµ áá¥á±á ášRDP áá®á¶á®áá áááá áááá«áᜠášášáá° á áá á¥á á áᢠá áá«á áá ášrdesktop á°áá á ášáá áš á²áá á á°áá£á á©á á á°ááá¢áŠáœ á¢ááááªáá áá€á¶áœ áá ášá°áá ášá° áá áá¢
áá®á¶á®á á¥ášá°á°áá áš á¥á«áᣠá áá®ááá± áá£á á áááŽáážá áááá«áµ á á²áµ á°áá£á áášáá á áµážá᪠ááᢠá áá á áááŽáážá áá ášá°á°ášá áááŠáœ á ááá¢áᜠáá«ášá áááµ áá¥ášááᣠáá á ášrdesktopâFreeRDP á¹á« á¥áá²áá á áááá«áµ áááᢠášááá± á°ášá᪠áµáááµ á GPLv2 áááµ ášá°áá°á á²áá áá á áá° Apache License v2 á¥áá°áá áááµ á¥áá²á°á¥ áá³á á áµá°áááᢠááá ááᣠááá á°á áá®á³ážá ááá±á áááášá á áá°áµáááᣠáµááá ááá¢áá¹ áá®ááá±á á¥áá°áá ááá»á áá°áᣠáá á ášá ááá ášá®áµ áá°ášáµ á áµášáµááá¢
áµá áá®ááá± á³áªá á°ášá᪠áááá®áœá á áŠááŽááá ášá¥áá áá¥á ááµá¥ ááááµ áá»ááá¡ "ášFreeRDP áá®áááµ á³áªá"á¢
á á®á± ááµá¥ áµá á°á¶áœá á¥á ááá ášááœá á°ááááá¶áœá áááášáµ á¥áá° áá³áªá«á£ á¥á á áá ááá áCᣠC++ᣠC# á¥á Java ášááááá³ááµ ášá®áµ á°áá³á á²áá á áááµáááᜠáá áááá Windows, Linux О macOS.
áœáá ášáá«ááá á á á£á á áµá°á³áœ ááá á«áááážáá áµá á°á¶áœ á¥á» ááá¢
ášáá á°áš áµááµá³ ááá°áµ
áš'cwd' á áááá á³ááá á°áá£á© áá¥á·áᢠášáá á°áš áµááµá³ ááá°áµ áá»ááᢠenvironment.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;
....
}
áá áá«á ášá°áá°á°á ášáááá áááµ áµáááµ á²ááᣠáá á á- á«ááá ášWINAPI áá á áá«ááœá ášáá«áµá°áá¥á ááá¢Windows áµááá¶áœá£ áááµáᣠááá áá¥á°áµ á«áá ášááá á ááá ááᢠá¥áá áá ááá°áµá áášáµ ááœááá¡ á á°áá£á© ášá°áá°á áá á°áš áµááµá³ getcwd, ášááááá áá© áá³á®áœá á²á«áµá°áááµ á¥á» ááᢠáµá á°á±á áááµá°á«ášá á¥áª áášá á«áµááááá³áᢠááá пПÑле áµááµá³.
ášáá°á áá á á°á«á°á
ášáµááµá áá»á áá»ááᢠáš'event->EventHandlerCount' á¢ááŽááµ á¥áŽáµ 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++;
}
....
}
á áá áá³áᣠášáá°á ášá€áááá¶áœ á¥ááµ á¢á°ášáµá á á²áµ á€ááááµ áá° áááá© áá³ášááᢠá¥áá ááᣠáŠáá¬á°á©á áá°á«áµ á á ááᢠ<= áá <ášáµááµá© áá°áᜠá¥áá³á«ááá¢
áá ášáá á áááµ áµá á°áµ á°ááá·áá¡
- ášV557 áµááµá áá»á áá»ááᢠáš'iBitmapFormat' á¢ááŽááµ á¥áŽáµ 8 áá°ááµ ááœááᢠorders.c 2623
á³áááµ
ááá 1
'!pipe->In' ášááá á áááᜠáááá áá°áµ ááᢠ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;
....
}
á¥áá áá ášá°ááá° ášáá°á á á»á»á á¥áá«ááá¡ ááá°áá ááá³ ášááááªá«á áá á°áá³á³á ášáá á°áááá áááµá»áᢠáµá á°á± ášáá£á á°á«á ášá®áµ á á-ááá á áááá«áµ ááá ááœááá¢
ááá 2
áááµ á°áá³á³á áœáá á«áážá á¥áá®áœ á°ááá°ááᢠááá°áá á¥áá ášáááášá ášááµáá 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);
....
}
áá ášáá°á á á»á»áá¡ ášá®áµ á áµá°á«ášáµ ášáá«áááá°á á¥ášá± ášá᪠ááá£áµ á¥áá³áá áµ áá á ááµá°á áµáªáµááá ááᣠáá£á¡ áá°á°á°ášá á°áááá áášá°á³á áá áµáªáµááá ááᣠáµá áá®á¶á®á á ááá áᣠáµááá áá ááá³á á¥á» ááá¢
ááá 3
áš'trio_index_last' á°áá£á á á«á áš'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);
}
á á áµá°á«ášá± áá°ášáµá£ á°áá£á© áµá«áá®_á¢ááŽááµ á á ááµ áá¥ášááá ááµá¥ ášá ááµ ááá ášááááªá« á°ááá á²á«áá áµá«áá®_á¢ááŽááµ_áášášá» â ášáášášá»áᢠááá áá ášá¥ááá á°áá£á«áµ á á«ááµ á°áá³á³á áážá! áááá£áµá áá ášáá°á á á»á»á áµá á°áµ ááᣠá¥á á á°áá£á© ááµá¥á¢ áµá«áá®_á¢ááŽááµ_áášášá» áá áá á«áµáááá áµáµááœá á áµáµááášáá«á á£á áªá á¥áá°á°á á áá ááááá¢
ááá 4
á á áááá¹ ááµá¥ á«áá 'á³á³' á áá áš nullptr áá á¥á©á ááᢠá áá á áá áá ášáá³á¥ áµá«áᜠáá€áµ áá áµááá ášáᜠáµááá á¥á á áá ááá ášáá áµáᢠ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;
....
}
á¥áá áá á áµáááµ ášáááœá áŠáá¬á°áá á«ááá¡ áááµááᢠ! á á á«á¢á« áášááá á³ááµá°áá ááá± á¥ááá³ ááá ááá¢
ááá 5
áš'if (A) {âŠ} á á ááá á áá ááá« (A) {âŠ}' ááµá á°ááá·áᢠášááá áµá á°áµ ášááá á¥áµá á áᢠááµáá®áœá á«ášááá¡á¡ 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);
}
....
}
ášáášášá»áá¹ áááµ ááá³áᜠá°áá³á³á áážáဠá ááµ á°á ášááá á á áá á¥áá±á ááá°áœ ášáµá¶áµ ááááᢠá®á± ášáášášá»á ááá ášá á«áµ á£ááµ á¥áŽá¶áœ áá á¥áá°áá°á« á«á³á«áᣠáµááá ášáášášá»á ááá³ ááá á áá áµ á¥áá ááááµ á¥ááœááá á¥áŽáµ <= 0x3FFFFFFFF.
áá ášáá á áááµ áµá á°áµ á°ááá·áá¡
- V517 áš'if (A) {âŠ} á á ááá á áá ááá« (A) {âŠ}' ááµá á°ááá·áᢠášááá áµá á°áµ ášááá á¥áµá á áᢠááµáá®áœá á«ášááá¡á¡ 169ᣠ173ᢠfile.c 169
ášáá€áµ ášááᥠáášááá«
ááá 1
'strcat(target, source) != NULL' ášááá á áááᜠáááá á¥áááµ ááᢠ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);
}
á áá áá³á ááµá¥ ášá°áá£á áá€áµ áášááá« ášá°á³á³á° ááᢠáµáµá«á«áµ áá° áá¥ášáááá ášáášášá» áµáªáµ á áá áááá³áᣠáááµá ášááááªá«á áááªá« á áááᢠá áá ááá³á£ á¥á± áá áááááá ááᣠá¥á©á ášáá á£á¶ášáá« á¥á±á áááá°áœ á á£á áááá·áᣠáááá«á±á á á°áá£á© ááµá¥ áµááá áµáµá«á«áµ áá°ášááá¢
ááá 2
'áážáá«' ášááá á áááᜠáááá á¥áááµ ááᢠ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)
{
....
}
....
}
á áá ááá³ á°ááááá áážáá« ášáµá³á²á áµááµá á áµá«á» á°ááµá§á áááá«áŒ -> áááá«áŒáµááá ᣠáŒá© ášáá (áážáá«) ááááµ ááœááá¢
ášáá¥áµ á áµá°á³á°á áµá á°áµ
áá¥á± ášá°ááá 'CreateFileA' á°áá£áá á áá áá ááᣠááá áá ášááá£á£á 'fclose' á°áá£áá á áá áá á°áááᢠcertificate.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;
}
....
}
ášááá ááá fpᣠá°áá£áá á áá¥á«áµ ášá°áá áš áá ááááᣠá á°áá£á á áµá á°áµ á°ááá·á fclose ášáá°á áá á€á°-ááœáááµá£ á áá°áá áá áááµá.
á°áá³á³á ááá³ááœ
á¥ááµ á á¥ááµ áá ááá ášááááµ áš'if' áááá«áᜠááá³á á ááááŸáœ á°áá³á³á áážáᢠááµáá®áœá á«ášááá¡á¡ 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);
}
....
}
áá áá³á áµá á°áµ áááá ááœááᢠáááᣠááá±á ááá³áᜠá°áá³á³á ááááá¶áœá ášá«á á²áá ášá¥ááá á ááµá¥ á áá± ááááµ ááœááá¢
á£á¶ á ááááœá ááœá³áµ
á£á¶ á ááá áá° 'áá»' á°áá£á áá°ááááᢠášááááªá«áá áááá ááááá©á¢ 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);
....
}
áááµá«áµ ááá á£á¶ á ááá ááá ááœááᣠá¥á á°áá³á áµáá± á«áááᢠááá áá á ááá áááá á£á¶ áá ášáá°áááá áµ ááá³ ášá°ááᣠáá á¥áá°áá áááááᣠááµá áááá« áá°á£áá¢
á áá mszGroupsA ááááªá« áá á¥á©á á£á¶ á¥á á áá áŠá³ á áá°ááášáᢠá ááá ááááá áµ ášááœáá áµ á¥ážáá ášá®áµ ááááµ áá°ášáµá áµ ášáááœá ááá¢
á¥áá°áá á áááµ ááᜠááááá¶áœá áá á©á¡
- V575 á£á¶ á ááá áá° 'áá»' á°áá£á áá°ááááᢠášááááªá«áá áááá ááááá©á¢ license.c 790
- V575 á£á¶ á ááá áá° 'áá»' á°áá£á áá°ááááᢠášááááªá«áá áááá ááááá©á¢ rdpsnd_alsa.c 575
áááá£áµá á¥áá°áá á«á ášá°ášá± á°áááá®áœ á ááá¶ áá°áµ áá°áµ áá áµ ááá³á á¥á á ááá áááá± ááœááá¢
áášá°áµ ášááœá ášáá á á áá ááá°áµ
áášá°áµ ášááœá ášáá á á áá ááá°áµá¢ ášáŠáá« áášá»ááœá á«áµá¡á áµá£ áá€á±á á áá°ááᢠ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));
....
}
áá€á±á áá° ááá£áµ ášá á áµáá± á«á± ášáášáááá á á ááá± á áá áá áµááá ášáá á á áá á¥áá³áááµ á°á ááá± ášá°á á á á áá°ááᢠint.
á ááµáááªá« áá ášá áá ááááá
áš'á ááµ' á ááá ášnullptr áá ášáášááá¡ á ááµ á¥á á áá áááᢠááµáá®áœá á«ášááá¡á¡ 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;
....
}
á ááá áážááá á ááµ á ááµáááªá« áá - ášááá°á¹ á ááµ - áá°ášááá¢
ááᜠášáá á áááµ áµá á°á¶áœ á°ááá°áááŠ
- V595 áš'ntlm' á ááá ášnullptr áá ášáášááá¡ á ááµ á¥á á áá áááᢠááµáá®áœá á«ášááá¡á¡ 236ᣠ255ᢠntlm.c 236
- V595 áš'á ááµ' á ááá ášnullptr áá ášáášááá¡ á ááµ á¥á á áá áááᢠááµáá®áœá á«ášááá¡á¡ 1003ᣠ1007ᢠrfx.c 1003
- V595 áš'rdpei' á áá ášnullptr áá ášáášááá¡ á ááµ á¥á á áá áááᢠááµáá®áœá á«ášááá¡á¡ 176ᣠ180ᢠrdpei_main.c 176
- V595 áš'gdi' á ááá ášnullptr áá ášáášááá¡ á ááµ á¥á á áá áááᢠááµáá®áœá á«ášááá¡á¡ 121ᣠ123ᢠxf_gfx.c 121
áµááá ášáᜠááá³
'rdp->state >= CONNECTION_STATE_ACTIVE' ášááá á áááᜠáááá á¥áááµ ááᢠconnection.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;
}
....
}
....
}
áá°á á²á á°áá³á á¥áŽáµ á ááá°á¡ áááá«áµ ášááááªá«á ááá³ áµááá á¥áá°ááá°á¥ áášáµ ááá ááá¢
ášá°á³á³á° ášáá¥ášááá áµáá°á
ášá°á³á³á° á áážáµá¢ áš'sscanf' á°áá£áá á¶áµá°ááá áµáááá áááá ááá°áœ á«áµá¡á áµá¢ áá° á«áá°áášá áš int á áááµ á áá áá á ááᢠproxy.c 220
ášááá³á á áááᜠááá áááá á¥áááµ ááá¡ (rc >= 0)ᢠproxy.c 222
static BOOL check_no_proxy(....)
{
....
int sub;
int rc = sscanf(range, "%u", &sub);
if ((rc == 1) && (rc >= 0))
{
....
}
....
}
á°áá³á ááá ááá áááµ ááµá áááá«ááœá áá°á£áᢠ%u ášá áááµ á°áááá áá á¥áá á«áá°áášá á¢áá²áá á°áááá áááµ á áááµ á áá intáá¥áᣠá á á«á£áª áá°á» á¥áá«ááá¡ á áá á á©á á«áá ááá³ ááá áµááá á áá°á¥áᣠáááá«á±á ášá áá± áá á ááááá áááá«áᢠášáá á®áµ á°á«á² áá á¥áá³á°á á ááá áᣠáá á¥áá áá ášáá ááá á ááᜠášá°á³á³á° ááá¢
á«áá°á°ášá°á© áŒá®áœ
'status == 0x00090314' ášááá á áááᜠáááá ášá°á³á³á° ááᢠ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;
....
}
ááááµ ášá°á°ášáá£ážá ááá³áᜠááááá ášá°á³á³á± ááááᣠáááá«á±á á áááá áá° ááá°áá ááá³ ášáá°áá°á ášáá á¥á» áá ááá³ == SEC_E_OKáµááááá á®áµ á¥áá°áá áááµá ááœáááŠ
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;
}
áá°áá°áá«
áµááá ášáá®ááá± áááá á áá«á³ áá³á®áœá áá á áµáááᣠááá áá á á£á á áµá°á³áœ ášáááµ á¥á» á áœáá ááµá¥ á°ááážááᢠášáá®áááµ ááá¢áᜠá áµáš-áá¹ áá ááá«á ášáááµ ááá á áá ášá áá®ááá±á á¥á«á³ážá ááááá ááœááᢠá¥áá²áá á áá³ááµ ášá°á³á³á± á ááá³á ááá®áœ áá á©á£ á¥ááá á ášá°áµá°á«ášá á°áá³áá ááá»á»á áášá³áᢠá«á ááᣠášá®áµ á¥á«áµá áá»á»á á¥á» á³ááá áµá á°á¶áœá áááááµ ášáá«á ááá áá ááááµ ášááá ášááááá³ááµ áµáá°á á áµááá ááᣠá¥á PVS-áµá±á²á® á áá ášááµ áášá³ ááœááá¢
áá á áœáá áá¥ááááá á°áá᪠á³á³ááᜠááá«áµ ášáááᣠá¥á£áá ášáµááá áááááá áá ááá¡ Sergey Lariná¢
ááá: hab.com
