PhantomSync: برنامج إخفاء سرقة محافظ العملات الرقمية من خلال حزم npm للعملات المشفرة

PhantomSync: ثماني حزم npm لمطوري العملات المشفرة تخفي برنامج تنزيل متأخرًا ومستمرًا ذاتيًا

TL؛ DR

قام ناشر واحد لـ npm بتوزيع ثماني حزم صغيرة تحمل أسماءً تشبه لبنات البناء اليومية لتطوير تقنية البلوك تشين والمحافظ الإلكترونية. base58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpersو crypto-validate-libيحتوي كل منها على أداة مساعدة فعّالة. ومع ذلك، يُلحق بهذه الأداة كتلة من التعليمات البرمجية ذاتية الاستدعاء تُنفذ فور استيراد الوحدة.

بعد حوالي 37 ثانية من الاستيرادتقوم هذه الكتلة بفك تشفير حمولة تأتي داخل الحزمة متنكرة في هيئة جهاز اختبار، وتكتبها إلى ملف مخفي ضمن دليل المستخدم الرئيسي، وتسجل نفسها لإعادة التشغيل في كل login يعمل هذا البرنامج على أنظمة ويندوز وماك أو إس ولينكس، ويُشغّل البرنامج النصي المُفكّك كعملية منفصلة. لا يتم تنفيذ أي شيء من هذا القبيل أثناء تثبيت npm؛ فهو ينتظر استيراد الكود وتشغيله، وهي فترة أقل ازدحامًا من عملية التثبيت.

البيانات ليست مبهمة. يتم شحنها كبيانات base64 عادية، لذا فإن فك تشفير "تركيبة الاختبار" يكشف المرحلة الثانية بالكامل: أ محفظة العملات المشفرة وسارق الأسرار التي تنتظر حتى يصبح الجهاز خاملاً، وتقوم بجمع المفاتيح الخاصة وعبارات الاسترداد، وتشفير كل عملية العثور عليها باستخدام مفتاح RSA-4096 مضمن في الكود، ثم تقوم باستخراجها عن طريق تثبيتها في وحدة تخزين IPFS العامة، وإرسال إشارة العودة كل 12 ساعة.

نتتبع المجموعة كـ مزامنة وهميةكانت جميع الحزم الثمانية موجودة في سجل npm وقت التحليل، وتم نشرها تحت حساب واحد.

النظام الإيكولوجيالآلية الوقائية الوطنية
الباقاتbase58-utils, abi-encode, eth-dev, arb-kit, layer2-sdk, solana-key-utils, eth-wallet-helpers, crypto-validate-lib
المنصات المستهدفةويندوز ، ماك ، لينكس
السلوك الأساسيأداة تحميل مؤجلة، يتم استيرادها في وقت محدد، مخفية كأداة اختبار؛ تقوم بتثبيت خاصية استمرارية البيانات عبر المنصات
الحمولةمحفظة عملات مشفرة ولص أسرار، تشفير RSA-4096، تسريب البيانات عبر تثبيت IPFS العام

تشريح الهجوم

تبدو كل عبوة عادية للوهلة الأولى. base58-utilsعلى سبيل المثال، هو عبارة عن بضعة كيلوبايتات من كود مساعد Base58 / Bitcoin-WIF لا يعتمد على أي مكتبات أخرى - وهو بالضبط ما يوحي به الاسم. يوجد الكود ذو الصلة في بعد الوحدة module.exports، حيث من غير المرجح أن ينظر القارئ الذي يتصفح الجزء العلوي من الملف: دالة ذاتية الاستدعاء تقوم بجدولة نفسها باستخدام مؤقت.

سلسلة العمليات، المعاد بناؤها من مصدر الحزمة، تعمل على النحو التالي:

1. Package is required() by the host project 2. A self-invoking function schedules a callback ~37,000 ms later (setTimeout) 3. On fire, the callback reads test/fixtures/keypairs.dat (a base64 blob) 4. It base64-decodes that blob into a Node.js script 5. It writes the script to ~/.cache-db/.node-sync/syncd.js (mode 0o700) 6. It installs login-persistence for that script (see below) 7. It spawns "node syncd.js" as a detached process

يبرز خياران تصميميان.

تنتقل الحمولة كجهاز اختبار. المرحلة الثانية ليست مكتوبة كشفرة برمجية واضحة. إنها موجودة في test/fixtures/keypairs.datملف base64، اسمه يندمج مع اسم حزمة تدّعي معالجة أزواج المفاتيح. بالنسبة لشخص يقرأ الملف المضغوط بسرعة، يبدو كبيانات نموذجية؛ أما بالنسبة للبرنامج المرفق، فهو عبارة عن نص برمجي لفك تشفيره وتشغيله. لا يحتوي برنامج التنزيل نفسه على عنوان شبكة - توجد هذه العناوين في المرحلة الثانية - ولكن لا يوجد أي تشفير إضافي: فالملف عبارة عن طبقة واحدة من base64، لذا فإن فك تشفيره (base64 -d) يستعيد كامل syncd.js وسلوك الشبكة الخاص بها. يشرح القسم التالي ما تفعله تلك المرحلة المستعادة.

يتم تأخير عملية التفجير وربطها بالاستيراد، وليس بالتثبيت. لأن المحفز هو يتطلب () بالإضافة إلى مؤقت مدته 37 ثانية تقريبًا بدلاً من خطاف التثبيت، يتجنب السلوك عمليات التحقق التي تراقب فقط تركيب npm وتستمر هذه الخطوة لفترة أطول من العديد من عمليات التشغيل التجريبية والتكامل المستمر قصيرة الأجل. وبحلول الوقت الذي يتم فيه تنفيذ أي شيء، تكون عملية التثبيت التي سحبت الحزمة قد انتهت منذ فترة طويلة.

بمجرد أن يصبح النص المشفر موجودًا على القرص في ~/.cache-db/.node-sync/syncd.js — مسار تم اختياره ليقرأ كدليل تخزين مؤقت روتيني — يجعل برنامج التثبيت هذا الدليل يعمل بعد إعادة التشغيل على جميع المنصات الرئيسية الثلاث:

  • لينكس: إدخال cron يُعيد تشغيل البرنامج النصي. يتم تثبيت الإدخال عن طريق تصفية crontab الحالي من خلال grep -v syncd، مما يؤدي إلى استبعاد الإدخال الجديد من قائمة بسيطة تبحث عن نفس الاسم.
  • نوافذ: مهمة مجدولة باسم WinNodeSync، ومن المقرر إعادة تشغيلها بفواصل زمنية مدتها 12 دقيقة.
  • ماك: مهمة launchd تحمل اسمًا com.apple.syncd، موجودة في العديد من العبوات - وهي عبارة عن ملصق يحاكي خدمة نظام أبل الأصلية.

ثم يتم تشغيل البرنامج النصي فورًا كعملية منفصلة، ​​بحيث يستمر في العمل بعد خروج البرنامج المستورد.

ما تفعله المرحلة الثانية

نظرًا لأن التركيب عبارة عن طبقة base64 واحدة، فإن المرحلة الثانية تُفك تشفيرها بسلاسة ويمكن قراءتها بالكامل. تحتوي جميع الحزم الثمانية على واحد من ثلاثة متغيرات لنفس النص البرمجي، والذي يُعرّف نفسه في تعليق رأسي على النحو التالي: المزامنة الوهمية v3 - أفضل ما في الأمر (يُطلق عليه اسم "الخلد النائم"). وتتمثل مهمته في سرقة بيانات محافظ العملات المشفرة وأسرار المطورين وإرسالها خارج الجهاز. ويتم تنفيذه وفق الخطوات التالية:

  • 1. انتظر حتى تتوقف الآلة عن العمل. قبل القيام بأي شيء، syncd.js يتحقق من مدة عدم نشاط المستخدم ولا يتابع إلا بعد تجاوز حد معين (حوالي 15 دقيقة) — com.xprintidle على Linux ، ioreg يُستخدم HIDIdleTime في نظام macOS، بينما يُستخدم استعلام PowerShell عن وقت الخمول في نظام Windows. ولذلك، غالباً ما تتم عملية جمع البيانات عندما لا يكون أحدٌ أمام لوحة المفاتيح.
  • 2. أحضر مفتاح تشغيل يتم التحكم فيه عن بعديسحب البرنامج النصي إعدادات صغيرة من مصدر مجهول قبل تنفيذه. المصدر الرئيسي هو رابط خام من GitHub gist (gist.githubusercontent.com/juang55/…/cfg.txtلا يتم تفعيل البرنامج النصي إلا إذا كانت إعدادات البرنامج النصي كالتالي: نشط=1إذا لم يكن المحتوى الأساسي متاحًا، فإنه يعود إلى ثلاثة معرّفات محتوى IPFS مُضمّنة في الكود، يتم جلبها عبر البوابات العامة. بوابة.بيناتا.سحابة, ipfs.ioو cloudflare-ipfs.comيمنح هذا المشغل إمكانية التحكم في التسليح/التعطيل بعد وقوع الحدث، بالإضافة إلى آلية احتياطية مقاومة للتفكيك. (أصغر نسخة، تم شحنها في مكتبة التحقق من صحة التشفير, مساعدو محفظة الإيثيريومو أدوات سولانا الرئيسية(تمت إزالة طبقة gist وتعتمد على معرّفات IPFS فقط.)
  • 3. جمع مواد المحفظة والأسرار. يقوم البرنامج النصي بتصفح دليل المستخدم الرئيسي — ~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~ / .sshو الحاسوب/المستندات/التنزيلات (بما في ذلك أسماء المجلدات باللغة الإسبانية)، بالإضافة إلى ~/.env وملفات rc الخاصة بالصدفة، وما يعادلها APPDATA مواقع على نظام ويندوز. يستهدف هذا البرنامج الخبيث مفاتيح إيثيريوم الخاصة، ومفاتيح بيتكوين WIF، وعبارات BIP-39، وأزواج مفاتيح سولانا، وملف JSON الخاص بمخزن مفاتيح إيثيريوم، ومفاتيح SSH، ومتغيرات البيئة التي تحتوي على أسرار. النسخة الأكبر (في ترميز ثنائي, base58-utils, eth-devيحتوي على قاموس BIP-39 الكامل المكون من 2048 كلمة ويستخدم التعابير النمطية لـ استخراج تستخدم هذه النسخة مفاتيح فردية وعبارات أساسية مُدققة من أي نص تقرأه؛ أما النسختان الأصغر حجماً فتستخدمان مطابقة الملفات حسب الكلمات المفتاحية (بذرة, ذاكري, محفظة, metamask, وهمي, دفتر الحسابات, trezor...) وتحميل الملفات كاملة.
  • 4. التشفير والتسريب من خلال خدمة تثبيت عامة. يتم إرفاق كل نتيجة ببصمة المضيف (اسم المستخدم@اسم المضيف(المنصة، الطابع الزمني) ويتم تشفيرها باستخدام مفتاح RSA-4096 عام مُضمّن في البرنامج النصي. ثم يتم تحميل السجل المُشفّر عن طريق تثبيته على IPFS عبر api.pinata.cloud/pinning/pinJSONToIPFSيتم التحقق من الهوية باستخدام بيانات اعتماد واجهة برمجة تطبيقات Pinata المضمنة في الكود. لا يوجد خادم تحكم/تحكم مخصص للاستيلاء عليه: فالبيانات المسروقة مخزنة في وحدة تخزين عامة لامركزية، ويمكن للمشغل استرجاعها باستخدام تجزئات المحتوى الناتجة. يتم تحميل البيانات بفواصل زمنية عشوائية لبضع ثوانٍ، ويتم الاحتفاظ بسجل محلي لـ الطابع الزمني | نوع المفتاح | التجزئة المُعادة يتم الاحتفاظ به في ~/.cache-db/.node-sync/.sl.
  • 5. استمر في المحاولة وكن منارة على مدار دورة مدتها 12 ساعة. تُعيد المرحلة الثانية ترسيخ استمراريتها الخاصة - وهي عبارة عن إدخال cron على نظام Linux، و com.apple.syncd تم تشغيل المهمة على نظام macOS، ومهمة مجدولة باسم مزامنة عقدة ويندوز على نظام ويندوز - مُعدّ لإعادة التشغيل كل 12 ساعة. لاحظ أن هذا مختلف اسم مهمة ويندوز من المهمة التي يقوم برنامج التثبيت بتثبيتها (WinNodeSyncكلاهما يستحق البحث عنه.

الخط الزمني

تم نشر الحزم الثماني دفعة واحدة في 13 و14 يوليو 2026. يحتوي بعضها على أكثر من إصدار واحد؛ ويكون برنامج التثبيت متطابقًا عبر جميع الإصدارات، مع اختلاف إزاحات الأسطر فقط بتغير حجم كود الأداة المساعدة غير الضارة الموجود أعلاه.

التاريخ الحدث/الفعالية
2026-07-13 تظهر الحزم الأولى في المجموعة تحت ناشر واحد (solana-key-utils, eth-wallet-helpers, crypto-validate-lib (والإصدارات المبكرة من البقية)
2026-07-13 → 07-14 تم نشر الأسماء المتبقية والإصدارات اللاحقة؛ نفس سفن التوزيع الملحقة في كل منها
2026-07-14 تم تحديد جميع الحزم الثمانية وتحليلها؛ ولا يزال بالإمكان تثبيت كل حزمة من السجل.

خلال فترة الانفجار، انتقلت سمعة سجل الناشر من محايدة تقريبًا في بداية المجموعة إلى سلبية بشدة مع تراكم عمليات الكشف - وهو أثر جانبي ملحوظ لوضع علامة على الحزم، وليس ميزة مصممة.

مؤشرات التسوية

تم التأكد من وجود جميع المؤشرات أدناه وقت التحليل - تلك الموجودة في جداول "المرحلة الثانية" عن طريق فك التشفير test/fixtures/keypairs.dat وقراءة ما تم استعادته syncd.js.

الملفات والمسارات

مؤشر النوع
~/.cache-db/.node-sync/syncd.js المرحلة الثانية التي تم فك تشفيرها، مكتوبة بالوضع 0o700
~/.cache-db/.node-sync/.sl سجل تسريب البيانات المحلي (الطابع الزمني | نوع المفتاح | تجزئة IPFS)
test/fixtures/keypairs.dat حمولة مشفرة بنظام Base64 موضوعة داخل ملف tarball كـ "جهاز اختبار"

البنية التحتية للشبكة في المرحلة الثانية (تم استعادتها من syncd.js)

مؤشر النوع
gist.githubusercontent.com/juang55/b298754cb72942b1cdcf02ccd45cde2f/raw/cfg.txt نقطة تسليم التفعيل؛ لا يتم تشغيل البرنامج النصي إلا إذا كانت الإعدادات تقرأ active=1
Qmcqz3w8j4qFQXDAXAxnrdc2oSX3nzBT4NqtpTqL8mr1ga خيار التراجع عن إعدادات IPFS (CID)
QmdTXoqVmTHY1i4ZWLdLkoQ9YChp5TXPh5cWXwnAYZt5iF خيار التراجع عن إعدادات IPFS (CID)
QmfJkLU5gdCpqbbqEjWYC2anXW9FmuEeSLLeLiHVJKYUjp خيار التراجع عن إعدادات IPFS (CID)
gateway.pinata.cloud, ipfs.io, cloudflare-ipfs.com بوابات IPFS المستخدمة لجلب إعدادات النسخ الاحتياطي
api.pinata.cloud/pinning/pinJSONToIPFS نقطة نهاية تسريب البيانات، البيانات المسروقة مثبتة على نظام ملفات IPFS العام
مفتاح واجهة برمجة تطبيقات بيناتا 13c766575b9270a9825dبيانات اعتماد استخراج البيانات المضمنة في الكود

أهداف التجميع في المرحلة الثانية (تم استعادتها من syncd.js)

مؤشر النوع
~/.config/solana, ~/.ethereum/keystore, ~/.foundry, ~/.hardhat, ~/.ssh, ~/.envملفات rc الخاصة بالصدفة تم البحث في المجلدات/الملفات عن المفاتيح والأسرار
AppData\Roaming\Solana, AppData\Local\ethereum\keystore تم البحث عن بدائل ويندوز
أنواع القطع الأثرية التي تم جمعها مفاتيح إيثيريوم الخاصة، وواجهة برمجة تطبيقات بيتكوين، وعبارات استعادة BIP-39، وأزواج مفاتيح سولانا، وملف JSON لمخزن مفاتيح إيثيريوم، ومفاتيح SSH، ومتغيرات البيئة السرية

آثار الثبات

المنظومة مؤشر
لينكس بدء تشغيل إدخال cron syncd.jsتم تثبيته عبر crontab وتمت تصفيته من خلال grep -v syncd
ويندوز مهمة مجدولة WinNodeSync (قطارة) WindowsNodeSync (المرحلة الثانية)
ماك علامة تجارية تم إطلاقها com.apple.syncd
الكل تستمر المرحلة الثانية في دورة مدتها 12 ساعة

السلوكية

  • تمت إضافة دالة ذاتية الاستدعاء بعد module.exports، جدولة setTimeout حوالي 37,000 مللي ثانية عند الاستيراد.
  • عملية الطفل spawn(“node”, ) مع تفعيل خيار الفصل.
  • التنشيط المُعتمد على البوابة الخاملة في المرحلة الثانية (com.xprintidle / ioreg وقت خمول HIDI / وقت خمول PowerShell؛ عتبة 15 دقيقة تقريبًا).
  • تشفير RSA-4096 لكل نتيجة، ثم HTTPS سأعين إلى واجهة برمجة تطبيقات تثبيت IPFS العامة.

الحزم والإصدارات (npm، الناشر solbuilder_io)

فئة الإشتراك إصدارات
base58-utils 1.0.0، 1.0.1، 1.0.3
abi-encode 1.0.0، 1.0.1، 1.0.2
eth-dev 1.0.0، 1.0.1، 1.0.2
arb-kit 1.0.0 , 1.0.1
layer2-sdk 1.0.0 , 1.0.1
solana-key-utils 1.0.0
eth-wallet-helpers 1.0.0
crypto-validate-lib 1.0.0

Publisher

  • solbuilder_io - angel_lopez89[@]proton[.]me، البريد الإلكتروني غير موثق، ولا يوجد حساب تحكم مصدر موثق، ولا يوجد مستودع مرتبط.

الإسناد والسلوك الملاحظ

تتشارك الحزم الثماني حساب ناشر واحد وحمولة واحدة. كل حزمة عبارة عن حزمة بسيطة - بضعة كيلوبايتات من التعليمات البرمجية المفيدة مع نفس أداة التثبيت الملحقة - منشورة بدون مستودع مرتبط وتحت بريد إلكتروني مؤقت غير موثق. هذا التوحيد، ومسار التثبيت المشترك، وعلامات الثبات المشتركة، و keypairs.dat ملفات التجهيز هي التي تربط المجموعة ببعضها البعض.

تتسم الطرود بصراحة غير عادية فيما يتعلق بسلوكها. أدوات سولانا الرئيسية يحتوي على تعليقات مضمنة تصف الكتلة الملحقة بعبارات بسيطة - إحداها تحمل عنوانًا. الشبح: المثابرة الخفيةويقول آخر (بالإسبانية) تنفيذ التوب في الخلفية"تشغيل البرنامج الخفي في الخلفية". هذه هي التعليقات التوضيحية الخاصة بالبرنامج لما يفعله؛ اسم الحملة في هذا المنشور مستمد من تلك التسمية الأولى بالإضافة إلى العقدة الوهمية "برنامج مزامنة الخادم" (متزامن) التي تحاكيها آلية الاستمرارية.

نقتصر في وصفنا على ما يفعله الكود بشكل واضح. تشير أسماء الحزم - وكلها مصطلحات متعلقة بالعملات المشفرة والمحافظ وأدوات البلوك تشين - إلى جمهور المطورين الأكثر احتمالاً لاستخدامها، ولا تُحدد هذه الأسماء وحدها هوية الناشر. كان من الممكن استعادة المرحلة الثانية بالكامل عن طريق فك تشفير بيانات base64، وقد وُصف سلوكها أعلاه: فهي تجمع مفاتيح المحافظ وعبارات الاسترداد والأسرار، ثم تُسرّبها مُشفّرة باستخدام RSA إلى وحدة تخزين IPFS عامة عبر Pinata. ومن أبرز خيارات التصميم غياب خادم C2 خاص - إذ يصل التكوين من ملف GitHub gist وIPFS، وتُخزّن البيانات المسروقة في وحدة تخزين عامة لامركزية مُفهرسة بتجزئة المحتوى، وكلاهما أصعب في الاستيلاء عليه من مضيف واحد يتحكم فيه المهاجم. لم يُعثر على أي تقارير عامة سابقة تُطابق هذه المجموعة وقت كتابة هذا التقرير.

من هو المعرض للخطر؟ أي شخص أضاف إحدى هذه الحزم إلى مشروع Node ثم قام بتشغيل كود يستوردها. ولأن التفجير يحدث أثناء الاستيراد وليس أثناء التثبيت، فإن مجرد وجود الحزمة لا يكفي، بل إن أي استخدام عادي يقوم بتحميل الوحدة يصل إلى الحمولة. تستهدف أسماء الطعم المطورين الذين يبنون على Ethereum وSolana وArbitrum وLayer-2 وأدوات المحفظة/التشفير العامة - وهم الفئة الأكثر احتمالاً لامتلاك الأصول التي تبحث عنها المرحلة الثانية. أي شخص قام بتشغيل إحدى هذه الوحدات على جهاز يحتوي على مفاتيح محفظة أو عبارات استرداد أو مخازن مفاتيح أو مفاتيح SSH أو .env ينبغي على المسؤولين عن إدارة الأسرار التعامل مع بيانات الاعتماد هذه على أنها مخترقة واستبدالها.

نمطان جديران بالاستيعاب. أولا، الحمولة كتركيب: شحن المرحلة الثانية بصيغة base64 داخل ملف بيانات يحمل اسمًا معقولًا (test/fixtures/keypairs.datيحافظ على مظهر المصدر المرئي للحزمة نظيفًا، ويدفع المحتوى الضار إلى ملف غالبًا ما تتعامل معه أدوات المراجعة والمراجعون البشريون على أنه بيانات خاملة. ثانيًا، التنفيذ المؤجل وقت الاستيراد مع استمرارية عبر المنصاتإن نقل المشغل من خطاف التثبيت، وإضافة مؤقت، ثم الاستمرار عبر cron والمهام المجدولة و launchd هو خطوة متعمدة للابتعاد عن تقنيات البرامج النصية للتثبيت الأكثر ضجيجًا والتي يراقبها فحص السجل الآلي عن كثب.

إرشادات للمدافعين والقائمين على الصيانة:

  • عالج الكود الملحق بعد module.exports كأولوية للمراجعة - غالبًا ما يختبئ منطق التثبيت تحت سطح الوحدة "الحقيقية".
  • لا تفترض أن ملفات البيانات خاملة. يوجد ملف بيانات ثنائي كبير (blob) بصيغة base64 تحت الاختبارات/التجهيزات/ يتم قراءة الملفات التي يتم فك تشفيرها أثناء التشغيل وتكون مجاورة للملفات التنفيذية؛ قم بتمييز عمليات قراءة ملفات البيانات أثناء التشغيل التي تغذي الوظيفة/وحدة التقييم/اكتب-ثم-نسل السلسلة.
  • ابحث عن مسار السقوط ~/.cache-db/.node-sync/ وبالنسبة لوحدات الثبات WinNodeSync (مهمة مجدولة) و com.apple.syncd (تم تشغيله) على أجهزة المطورين التي سحبت هذه الأسماء.
  • تنبيه بشأن عمليات Node التي تنشئ إدخالات cron أو مهام مجدولة أو وظائف launchd - نادرًا ما تقوم المكتبات الشرعية بذلك عند الاستيراد.
  • يُفضّل استخدام ملفات القفل والإصدارات المثبتة، ومراجعة الفرق بين أي تبعية "مساعدة" صغيرة جديدة، وخاصةً تم نشر حزم بدون تبعيات بواسطة حسابات غير موثقة بدون مستودع مرتبط.

بالنسبة لمدافعي السجل، فإن الخلاصة هي أن مراقبة خطاف التثبيت ضرورية ولكنها غير كافية: فبرنامج التثبيت الذي يتم تحميله في وقت الاستيراد والمؤقت والموجود داخل ملف بيانات سيجتاز فحص وقت التثبيت فقط، وغالبًا ما تكون خطوة الاستمرار هي الإشارة الأكثر وضوحًا التي يجب رصدها.

أدوات تحليل التركيبات البرمجية sca
إعطاء الأولوية للمخاطر التي تتعرض لها برامجك، ومعالجتها، وتأمينها
احصل على حسابك المجاني.
أي بطاقة ائتمان.

قم بتأمين تطوير البرامج الخاصة بك وتسليمها

مع مجموعة منتجات Xygeni