
الفصل 1. الضيوف غير متوقع
بدأ كل شيء في ذلك الصباح المشؤوم عندما أعلن مدير المشروع أن المواعيد النهائية لتنفيذ المشروع يجب أن تقل بسرعة وحسم لمدة شهر. بتعبير أدق ، يجب أن يكون المشروع جاهزًا خلال 4 أيام. لا ، صندوق بريدنا ليس وحشًا ، ولا يبدو مثل
البومة (ربما يشبه الغراب تمامًا) ، لقد حدث بالفعل. حسنًا ، إذا كان ذلك ضروريًا ، فهذا ضروري ، خاصة وأن الفريق (وأنا المطور الرئيسي لفريق "C") قد وعد بشيء لذيذ. كانت الساعة والتقويم الخميس ، 11:00 ، بحلول يوم الاثنين ، يجب أن يكون المشروع جاهزًا.
بالنسبة للمبتدئين ، ماذا نفعل على الإطلاق. نحن نشارك في أتمتة دور السينما - التحكم التلقائي عن بعد في المعدات ، وأتمتة عرض الأفلام ، والرصد ، ولوحات الفيديو ، وكذلك الآن محطات لبيع التذاكر والحانات. على وجه التحديد ، تم تخصيص الفقرة الأخيرة لهذه المقالة.
المشروع نفسه ، الذي كان من المفترض أن يكتمل قبل يوم الاثنين ، هو نوع من الطبقات بين الخادم الرئيسي في سكالا ومحطة الدفع الحديدية VeriFone VX 820 (في الواقع ، هناك المزيد من المحطات الطرفية ، ولكن في مثال على ذلك). من الواضح أن لا أحد سوف يعطينا معاملات من خلال ذلك تمامًا ، لذلك يتم استخدام الأدوات المساعدة ومكتبات Sberbank / Arcus و UCS. وبالتالي ، ينبغي أن يكون مخطط العمل في نهاية المطاف على النحو التالي:

ظاهريا ، يبدو كالتالي:

أيضًا ، يجب استخدام هذا النظام الفرعي في سجلات النقد القياسية التي شاهدها الجميع في أي من دور السينما في الصندوقين.
وفقًا للتقاليد الداخلية ، نسمي كل مشروع من فريقنا اسمًا من أساطير Old Norse ، لهذا النظام الفرعي تم اختيار Gefjon - اسم آلهة الخصوبة والخصوبة (اسم جيد لخادم الدفع ، أليس كذلك؟ الأسطورة حول الثيران تقطع الجزيرة بشكل مثالي قطع العمل بالمعدات عن لغة عالية المستوى).
تنسيق الرسائل الواردة والصادرة هو خادم HTTP مع تحميل JSON. هذا هو الحل الأمثل بين Scala ، والذي يصعب الوصول إليه لعزل البيانات الثنائية من تدفقات المقبس و C ، وهو أمر يصعب الوصول إليه لنقل الكائنات عبر الشبكة. لا توجد العديد من العمليات المحتملة التي يجب تشغيلها: الدفع والإلغاء والعودة وأنواع مختلفة من التقارير وفتح قائمة الخدمة والاتصال. لا يبدو شيئا معقدا. نظرًا لوجود ثلاثة أنظمة بنكية (ومن المتوقع تجديد موارد الأسرة لاحقًا) ، فقد تقرر تقسيم المشروع إلى مكونات:

الكتل الخضراء هي تلك التي نحتاج إلى صنعها ، والأزرق هي الكتل التي لا يمكن تغييرها والتي يوفرها البنك.
نظرًا لأن المشاكل الرئيسية نشأت فقط مع برنامج من Sberbank ، سيتم تخصيص المقالة ككل للمخاطر ، التي عدناها باستخدام قاربتنا.
الفصل 2. لحم الضأن المشوي

(الصورة: heaclub.ru)
... يبدو شيء من هذا القبيل. رمز هذا النموذج الأولي ، الذي كتب قبل بضعة أشهر من أجل توضيح لجميع الناس أعلى أننا يمكن أن تعمل مع التطبيقات المصرفية ، بدا نفس الشيء.
char buf[BUF_KB * 2]; char * null; char * grep; #ifdef _WIN32_WINNT char * ptr; null = "nul"; grep = "findstr"; #else null = "/dev/null"; grep = "grep"; #endif sprintf(buf, "%s %"PRIi32"= %sops.ini >%s 2>%s || " "echo %"PRIi32"=9,6,PINPAD_TEST >> %sops.ini", grep, TERM_ARCUS_TEST_PINPAD, TERM_PATH, null, null, TERM_ARCUS_TEST_PINPAD, TERM_PATH); #ifdef _WIN32_WINNT ptr = buf; while (*ptr) { if (*ptr == '/') *ptr = '\\'; ptr++; } #endif
من الواضح أن هذا لم يكن مناسبًا لإصدار الإنتاج ، لذلك كان من الضروري بشكل أساسي كتابة كل شيء من جديد.
عادةً ما يوفر كل بنك يوفر مكتبات للعمل مع الجهاز خيارين للاتصال: من خلال وظائف المكتبة (.so / .dll) أو من خلال أداة مساعدة جاهزة تحتاج فقط إلى تمرير قيمتين - نوع العملية والمبلغ (عند الحاجة). من الناحية النظرية ، لا شيء معقد ، مجرد شيء
char buffer[100]; sprintf(buffer, "%d %d", atoi(argv[1]), atoi(argv[2])); system(buffer);
سيتم وضع نتيجة العملية في الملف "e" ، والتحقق من الانزلاق في الملف "p". ما عليك سوى إرسال هذه الملفات إلى stdout مع التحويل إلى JSON ، بحيث يرسلها خادم HTTP كحمولة دون التفكير في ما هو موجود.
لكن هذا المقال ما كان ليتم نشره لو كان كل شيء بهذه البساطة.
الفصل 4. عبر الجبل وتحت الجبل
كان الإصدار الأولي للتطبيق عبارة عن دعوة تطبيق بسيطة - خادم HTTP يسمى المجمع الضروري مع المعلمات الموحدة (على سبيل المثال ، تقرير X هو 4) ، والأداة المساعدة ، على سبيل المثال gfj_pilot ، أطلقت sb_pilot مع المعلمة المطلوبة لهذه العملية (على سبيل المثال ، فإن تقرير X هو 9) . ثم تقرأ الأداة المساعدة للالتفاف نتيجة العملية من الملف الإلكتروني (على سبيل المثال ، 2000 - "تم رفض الدفعة ، كرر العملية") وحولتها إلى خطأ عالمي (على سبيل المثال 3 - "خطأ في قراءة البطاقة / الحساب أو معالجته ، كرر العملية"). بعد ذلك ، تم تحويل الملف "p" إلى base64 لتجنب كسر التنسيق وإرساله مع النتيجة إلى stdout كـ JSON.
كل هذا يعمل بشكل جيد حتى في لحظة واحدة على علم بأن ...
... هذا لا يعمل تحت ويندوز.

حسنًا ، بشكل أكثر دقة ، لا يواجه Windows نفسه أي مشاكل (باستثناء أن الشريحة يتم إنشاؤها في تشفير Cp-1251 ، وأن وحدة التحكم تعمل في CP866). ببساطة لم يتم إنشاء الملف "e". أطلقت الأداة المصرفية مباشرة:
C:\banks\sber\sb_pilot>dir C . : B401-6B9D C:\banks\sber\sb_pilot 04.02.2019 12:28 <DIR> . 04.02.2019 12:28 <DIR> .. 31.01.2019 17:12 10 832 F12X24.BIN 31.01.2019 17:12 128 000 gate.dll 31.01.2019 17:12 72 192 loadparm.exe 31.01.2019 17:12 36 204 OPT0.R 31.01.2019 17:12 20 716 OPT1.R 31.01.2019 17:12 1 806 OPT3.R 31.01.2019 17:12 388 608 pilot_nt.dll 31.01.2019 23:06 463 pinpad.ini 31.01.2019 17:12 91 136 posScheduler.exe 31.01.2019 17:12 418 printers.ini 01.02.2019 16:51 91 646 sbkernel1902.log 31.01.2019 17:12 653 312 sbrf.dll 31.01.2019 17:12 840 192 SBRFCOM.dll 31.01.2019 17:12 3 142 656 sb_kernel.dll 01.02.2019 16:51 9 SESS.D 01.02.2019 16:51 715 SPLC.D 31.01.2019 17:12 72 192 upwin.exe 20 5 659 718 2 37 567 004 672 # (1) 10 (1000 ) C:\banks\sber\sb_pilot>loadparm.exe 1 1000 C:\banks\sber\sb_pilot>dir C . : B401-6B9D C:\banks\sber\sb_pilot 04.02.2019 12:28 <DIR> . 04.02.2019 12:28 <DIR> .. 04.02.2019 12:28 216 commerr.log 31.01.2019 17:12 10 832 F12X24.BIN 31.01.2019 17:12 128 000 gate.dll 31.01.2019 17:12 72 192 loadparm.exe 31.01.2019 17:12 36 204 OPT0.R 31.01.2019 17:12 20 716 OPT1.R 31.01.2019 17:12 1 806 OPT3.R 01.02.2019 18:51 1 349 p 31.01.2019 17:12 388 608 pilot_nt.dll 31.01.2019 23:06 463 pinpad.ini 31.01.2019 17:12 91 136 posScheduler.exe 31.01.2019 17:12 418 printers.ini 04.02.2019 12:28 92 218 sbkernel1902.log 31.01.2019 17:12 653 312 sbrf.dll 31.01.2019 17:12 840 192 SBRFCOM.dll 31.01.2019 17:12 3 142 656 sb_kernel.dll 01.02.2019 16:51 9 SESS.D 01.02.2019 16:51 715 SPLC.D 31.01.2019 17:12 72 192 upwin.exe 19 5 659 029 2 37 567 008 768 C:\banks\sber\sb_pilot>
في الواقع ، لا يوجد ملف "e". الحجر نحو سبيربنك # 1. نكتب خطابًا إلى سبيربنك (تلقينا لاحقًا إجابة مفادها أنه ينبغي أن يكون الأمر كذلك) ، ولأنه لا يوجد وقت للمراسلات وعلينا أن نبدأ الآن ، نحن نبحث عن حلول للحصول على النتيجة.
04.02 12:28:55 SBKRNL: Failed to open device \\.\COM1, err 2 04.02 12:28:56 SBKRNL: Failed to open device \\.\COM1, err 2 04.02 12:28:56 SBKRNL: Result = 0 04.02 12:28:56 GATE: unlock:'00000054' 04.02 12:28:56 GATE: lock:'00000054' 'UPOSWINMUTEX2' 04.02 12:28:56 GATE: unlock:'00000054' 04.02 12:28:56 LOADPARM: Unloading GATE.DLL... 04.02 12:28:56 GATE: SB_KERNEL.DLL is unloaded 04.02 12:28:56 LOADPARM: GATE.DLL unloaded
نعم ، يمكن الحصول على النتيجة من سجل sbkernel.log. بشكل غير مريح ، بالإضافة إلى عدم وجود تجزئة الخريطة المسمار لاحقًا "شكرًا لك" من سبيربنك. ليس جيد
سيكون عليك الاتصال بمكتبة pilot_nt.dll واستيراد وظائف منها. سيكون كل شيء على ما يرام ، ولكن ... حجر أساسي تجاه Sberbank # 2: لا توجد مكتبة من هذا القبيل في نظام Linux ، سيتعين عليك إنشاء تطبيقين مختلفين لأنظمة تشغيل مختلفة - لنظام التشغيل Linux ، اتصل بأداة sb_pilot (على غرار loadparm.exe ، بالمناسبة رقم # 3 للحصول على اسم أداة مساعدة مختلفة ضمن أنظمة تشغيل مختلفة ) ، تحت ويندوز الاتصال مكتبة pilot_nt.dll.
الفصل 5. الألغاز في الظلام
في الساعة 19:00.
Sberbank هي شركة كبيرة ، ويتم إنتاج معظم حلول البرامج وفقًا لمعايير GOST والوثائق الرسمية. ندخل في الكتالوج الذي يزوده سبيربنك بالمكتبات:
Sberbank$ ls -l Docs 30160 drwx------ 2 alex alex 4096 17 19:31 FAQ -rw-rw-r-- 1 alex alex 3398465 9 2018 UPOS ().docx -rw-rw-r-- 1 alex alex 1182078 9 2018 UPOS .docx -rw-rw-r-- 1 alex alex 853504 9 2018 .doc drwx------ 3 alex alex 4096 31 17:11 -rw-rw-r-- 1 alex alex 5280787 9 2018 POS-.docx -rw-rw-r-- 1 alex alex 1149640 9 2018 .docx drwx------ 2 alex alex 4096 28 2018 UPOS drwx------ 2 alex alex 4096 28 2018 -rw-rw-r-- 1 alex alex 3451601 9 2018 ().docx -rw-rw-r-- 1 alex alex 1956196 9 2018 .docx -rw-rw-r-- 1 alex alex 1043161 9 2018 ()_().docx -rw-rw-r-- 1 alex alex 4348157 9 2018 POS-.docx -rw-rw-r-- 1 alex alex 3970267 9 2018 .docx drwx------ 3 alex alex 4096 28 2018 -rw-rw-r-- 1 alex alex 2644702 9 2018 POS-.docx drwx------ 2 alex alex 4096 28 2018 -rw-rw-r-- 1 alex alex 1558211 9 2018 .png
كثير من الخير ، لكننا مهتمون فقط بدليل المطورين:
Sberbank$ ls -l Docs/\ \ \ / 8704 -rw-rw-r-- 1 alex alex 47105 9 2018 1C.docx -rw-rw-r-- 1 alex alex 1824 9 2018 cardtype.h -rw-rw-r-- 1 alex alex 2590378 9 2018 cr_ttk_protocol_ru.rtf -rw-rw-r-- 1 alex alex 208 9 2018 deprtmnt.h -rw-rw-r-- 1 alex alex 16681 9 2018 errors.h drwx------ 6 alex alex 4096 28 2018 examples -rw-rw-r-- 1 alex alex 58575 9 2018 gate.h -rw-rw-r-- 1 alex alex 4218 9 2018 paramsln.h -rw-rw-r-- 1 alex alex 61693 9 2018 pilot_nt.h -rw-rw-r-- 1 alex alex 28160 9 2018 ReadTrack2.doc -rw-rw-r-- 1 alex alex 7417 9 2018 sbkernel.h -rw-rw-r-- 1 alex alex 144896 9 2018 sb_pilot.doc -rw-rw-r-- 1 alex alex 3525323 9 2018 ole- sbrf.dll.rtf -rw-rw-r-- 1 alex alex 46683 9 2018 gate.dll.chi -rw-rw-r-- 1 alex alex 255414 9 2018 gate.dll.chm -rw-rw-r-- 1 alex alex 814653 9 2018 gate.dll.pdf -rw-rw-r-- 1 alex alex 41618 9 2018 pilot_nt.chi -rw-rw-r-- 1 alex alex 241716 9 2018 pilot_nt.chm -rw-rw-r-- 1 alex alex 968753 9 2018 pilot_nt.pdf -rw-rw-r-- 1 alex alex 81 9 2018 .txt
الكثير من النفايات الورقية ، فقط في حالة إعادة قراءة pilot_nt ، والتي نتعلم منها ما يلي:
الجدول 1. دعم نظام التشغيل sb_pilot.
اتضح أن الأداة المساعدة للنوافذ يجب أن تظل تسمى sb_pilot. حسنًا ، حجر نحو Sberbank # 4 لعدم تناسق الوثائق الخاصة به.
نقل نتائج البرنامج.
في نهاية البرنامج ، يتم تشكيل ملفين نصيين - ملف التبادل وملف التحقق.
الأول يدعى e ويهدف إلى تمرير معلمات العملية المثالية لبرنامج الاستدعاء. يحتوي السطر الأول في هذا الملف على رمز نتيجة العملية ، ونص مفصول بفواصل يوضح الرسالة النصية. الرمز 0 يعني الدفع الناجح ، أي رفض أو عدم القدرة على الدفع.

كسول نرمي حجرًا واحدًا ونبدأ في دراسة الوثائق لربط المكتبة مباشرة.
الإجراء لاستدعاء وظائف المكتبة
عند سداد (إعادة) المشتريات عن طريق بطاقة الائتمان ، يجب أن يتصل البرنامج النقدي بوظيفة card_authorize () من مكتبة Sberbank عن طريق ملء حقول TType و Amount وتحديد قيم صفرية في الحقول المتبقية. في نهاية الوظيفة ، تحتاج إلى تحليل حقل RCode. إذا كانت تحتوي على القيمة "0" أو "00" ، فسيتم اعتماد التفويض بنجاح أو يتم رفضه. بالإضافة إلى ذلك ، يجب عليك التحقق من قيمة حقل التحقق.
إذا لم يكن الأمر NULL ، فيجب إرساله للطباعة (في الوضع غير المالي) ثم
حذف عن طريق استدعاء الدالة GlobalFree (). عند إغلاق نوبة عمل ، يجب على البرنامج النقدي استدعاء دالة close_day () من مكتبة سبيربنك عن طريق ملء حقل TType = 7 وتحديد قيم صفرية في الحقول المتبقية. في نهاية الوظيفة ، تحقق من قيمة حقل التحقق.
إذا لم يكن حقل "التحقق" فارغًا ، فيجب إرساله للطباعة (في الوضع غير المالي) ثم حذفه عن طريق استدعاء وظيفة GlobaFree ().
يبدو سهلاً ، حتى يتم توفير ملف رأس. حسنًا ، قم بتوصيله وتجميعه و ...
$ cat main.c && i686-w64-mingw32-gcc main.c -o main.a #include "pilot_nt.h" int main(void) { return 0; } In file included from main.c:1:0: pilot_nt.h:525:3: error: unknown type name 'auth_answer' auth_answer ans; ^ pilot_nt.h:544:3: error: unknown type name 'auth_answer' auth_answer ans; ^ pilot_nt.h:567:3: error: unknown type name 'auth_answer' auth_answer ans; ^ pilot_nt.h:590:3: error: unknown type name 'auth_answer' auth_answer ans; ^ pilot_nt.h:627:3: error: unknown type name 'auth_answer' auth_answer ans; ^ pilot_nt.h:668:3: error: unknown type name 'auth_answer' auth_answer ans;
أم ... ماذا؟ افتح pilot_nt.h:
#ifdef __cplusplus extern "C"{ #endif <...> /** * * , . */ struct auth_answer{ int TType; /**< [in] . ::OpetationTypes */ unsigned long Amount; /**< [in] */ char RCode[3]; /**< [out] */ char AMessage[16]; /**< [out] */ int CType; /**< [in,out] */ char* Check; /**< [out] , GlobalFree */ }; <...> struct auth_answer7{ auth_answer auth_answ; /**< [in, out] . . ::auth_answer */ <---- THIS char AuthCode[MAX_AUTHCODE]; /**< [out] . 7 . */ char CardID [CARD_ID_LEN]; /**< [out] . 25 . */ int SberOwnCard; /**< [out] */ };
على الفور ، دون النظر إلى الحجر للتعليقات باللغة الروسية في الترميز CP1251.
حسنا ، أخطر حجر: عزيزي المطورين C ++. إذا كتبت extern "C" ، فهذا يعني أن الشفرة داخل الكتلة يجب أن يتم تجميعها بواسطة برنامج التحويل البرمجي C. إذا لم تكن قد صنعت "typedef" للهيكل ، فحينما تذكرها كمرجع كتابة ، يجب عليك كتابة الكلمة الأساسية `struct`.
قم بتصحيح الملف للمطورين ، واستبدل كلمة `struct` أينما دعت الحاجة. الارتباط بمكتبة `pilot_nt.dll النصر ، لا؟ نطلق تطبيقنا.
الفصل 6. من النار إلى النيران
حسنا ، هل تفهمها ، أليس كذلك؟ تعطل التطبيق فقط. وصولا الى الرئيسية. التأمل ، أضف تمثيلا NIH الخاص بوظيفة errno لنظام windows: GetLastError (الحجر رقم 3 تجاه Microsoft ، الأولان مخصصان للترميزات).
C:\banks\sber\WIN>sb_pilot.exe 1 1000 E: !g_sblibrary (0xc0000096)
0xc0000096؟ لا ينبغي أن يُرجع GetLastError رمز خطأ مناسب؟
للحصول على قائمة كاملة برموز الأخطاء التي يوفرها نظام التشغيل ، راجع رموز أخطاء النظام.
نعم ، افتح المقال
هنا :
توفر المواضيع التالية قوائم رموز خطأ النظام. يتم تعريف هذه القيم في ملف رأس WinError.h.
- رموز خطأ النظام (0-499) (0x0-0x1f3)
- رموز خطأ النظام (500-999) (0x1f4-0x3e7)
- رموز خطأ النظام (1000-1299) (0x3e8-0x513)
- رموز خطأ النظام (1300-1699) (0x514-0x6a3)
- رموز خطأ النظام (1700-3999) (0x6a4-0xf9f)
- رموز خطأ النظام (4000-5999) (0xfa0-0x176f)
- رموز خطأ النظام (6000-8199) (0x1770-0x2007)
- رموز خطأ النظام (8200-8999) (0x2008-0x2327)
- رموز خطأ النظام (9000-11999) (0x2328-0x2edf)
- رموز خطأ النظام (12000-15999) (0x2ee0-0x3e7f)
حسنًا ، لقد حصلنا على خطأ غير موثق ، ونلقي بالحجر ونفتح google كلي العلم:
جوهر الخطأ هو أن بعض الروتين الفرعي يستخدم أحد الإرشادات
- _inp ()
- _inpw ()
- _inpd ()
- _outp ()
- _outpw ()
- _outpd ()
يحظر استخدام ذلك تحت مراكز NT ، حيث يحاولون العمل مع المنفذ المتوازي مباشرةً. على ما يبدو ، يتم استدعاء هذا الرمز في مُهيئ المكتبة ، أي ترغب المكتبة عند بدء التشغيل في استقصاء المنافذ للأجهزة ، ولكن يتطلب kernel NT العمل من خلال برنامج التشغيل.
الوضع ميؤوس منها؟
الفصل 8. العناكب والذباب
10 مساءً فقط في حالة نشوء الفكرة للتحقق من أن هذا لا يرجع إلى حقيقة أننا نستخدم الترجمة المتقاطعة مع Linux باستخدام mingw. في الوقت نفسه ، نحن ندرك أن Sberbank يقدم تطبيقًا 32 بت فقط ، لذلك لن يعمل مع تطبيق 64 بت ، حسنًا ، لكننا سنطلق حجر الأساس نحو Sberbank للإصدار 32 فقط في عام 2019.
المقدمة : مثبتة على windows 7 windowsbox.
مطلوب : تثبيت Visual Studio ونسخ MVP.
نذهب إلى موقع Microsoft على الويب ، ونقوم بتنزيل Visual Studio 2017. نأخذ ترخيص المجتمع ، نظرًا لأننا نتحقق منه للتحقق ، فسيتم شراء الترخيص إذا تم الإقلاع عنه.
نزّل بضع مئات من الميجابايت و ...
نرى أن إصدار نظام التشغيل (Windows 7) الخاص بنا غير مدعوم.
حسنًا ، نذهب إلى جميع أنواع المواقع الفاحشة ، نحن نبحث عن Visual Studio 2008 ، ونقوم بتنزيل بضع مئات من الميجابايت مرة أخرى و ...
نحصل على ملف ISO.
حسنًا ، دعنا نحاول تثبيت Daemon Tools 10 (نظرًا لأن هذا هو الإصدار الذي يقدمه الموقع) لإدخال هذا القرص الظاهري.
قم بتشغيل binar الذي تم تنزيله. اختل ، يتطلب .NET Framework 4.5 ، تنزيل ، تثبيت.
نبدأ في تنزيل binar ، وقد بدأ التثبيت ، ويقول أداة تحميل التشغيل أنه يحتاج إلى 4.5.2 ، تنزيل ، تثبيت.
نبدأ تشغيل binar الذي تم تنزيله ، وقد بدأ التثبيت ، ويقول محمل الإقلاع إنه لن يذهب إلى أي مكان حتى نقوم بتثبيت التحديث الأمني KB3033929 ، التنزيل ، التثبيت.
ونحصل على صفعة في الوجه من Microsoft كرسالة:

نحن نرمي بعنف حجرًا حادًا تجاه Microsoft ، وننزل أدوات Daemon Tools القديمة من السيول ، ونجح في إلغاء تثبيت Visual Studio ، والتثبيت ، وتجميع MVP (00:00) ، ونحصل على الخطأ نفسه. حسنًا ، كانت هناك نسخة جيدة ، لكنها لم تنمو معًا.
الفصل 11. على العتبة
نكتب للمبرمج الثاني الذي يكمل في هذه اللحظة الخادم وإجراءات التسجيل بشكل عاجل. يتذكر أن هناك
مستودع بوابة يتصل بهذه المكتبة على NT ويعمل معها.
عند البحث بشكل مثير للريبة عن المستودع ، قم بتنزيله وتجميعه وتشغيله. إنه يعمل.

نحن ننظر إلى رمز أكثر مثير للريبة. الكود مطابق ، إلا أنه مكتوب بلغة C ++ وليس C.
نحن نفهم أن اللغة لا علاقة لها بها. ننظر إلى مكتبات سبيربنك التي تسحبها الكود.
نرى الالتزام الأخير.
وهنا ننتظر مفاجأة أخرى.
اتضح أن إصدارات مكتبة سبيربنك قد تكون مختلفة. الالتزام الأخير يزيد الإصدار من 23 إلى 27. انسخ الإصدار من gita إلى كمبيوتر الاختبار - يعمل!
نحن نتحقق من جميع المحفوظات التي أرسلها سبيربنك ، ومقارنة الإصدارات وبناء جهاز لوحي:
عظيم ، والآن دعونا نشفى. في تلك الأنظمة حيث تكلف 26 ، قم بالترقية إلى 29 أو 27 وكل شيء سينطلق.
نرمي الحجر رقم 9 نحو سبيربنك لكسر السلوك على أنظمة NT.
الفصل 12. ما الذي ينتظرهم في الداخل
لا يكفي ملف ه؟ لا يهم ، فنحن نأخذ عناوين مصححة ، ونربط ديناميكيًا بالمكتبة لإرجاع خطأ بشكل صحيح ، وكتابة رمز يكتب ببساطة رمز الإرجاع من الوظيفة إلى ملف "e" ، دعونا ندعو biner sb_pilot.exe و ...
للعمل ، إنه يعمل.
هذا مجرد إصدار لنظام "Cryptor" لا يقوم بإنشاء ملف "p".
نحن ننظر بحزن إلى الدماء التي تتساقط على المفاصل وعلى الأسنان في الجدار.بالنسبة للمبتدئين ، ما هو نظام Cryptor.
Cryptera هي شركة دنماركية تنتج معدات التشفير / معدات / مفاتيح الأمان ، إلخ. أعتقد أنك شاهدت جميعًا نسخة من منتجاتها:

لذا ، يستخدم سبيربنك وحدة التشفير الخاصة بهم للوحات المفاتيح ويصدر مكتبة خاصة "مصححة" ، والتي ، كما فهمنا بالفعل ، لا يتم إنشاء ملف "p". نكتب إلى سبيربنك حول هذا الموضوع وفي غضون أيام قليلة ، سوف نحصل على الجواب بأنه "بموجب النظام الأصلي ، سيتم إنشاء الملف" p "، لكن في ظل نظام الترقيع إلى Cryptor ، لن يتم ذلك." سنمنحهم الحجر رقم 10 في غضون أيام قليلة ، لأنك بحاجة إلى العمل الآن.
لحسن الحظ أو لسوء الحظ ، فإن الوظائف التي نستخدمها لإجراء العمليات ترجع الهيكل المذكور بالفعل:
struct auth_answer{ int TType; unsigned long Amount; char RCode[3]; char AMessage[16]; int CType; char* Check; };
أوه ، حسنًا ، الشيك موجود بالفعل ، يمكننا حفظه في ملف بأنفسنا أو طباعته على الفور في JSON ...
printf("%s\n", answer.Check);
وحصلنا على تعطل التطبيق بسبب الوصول إلى مؤشر غير صالح.
الفصل 14. النار والماء
4 صباحًا نقوم بأداء Seth Bandha Sarvangasana لتهدئة ، وقراءة الدليل بعناية:
[الخروج] صورة الشيك ، يجب تحريرها بواسطة GlobalFree في برنامج الاتصال
ماذا يعطينا هذا؟ كثير أولاً ، نظرًا لأنه يلزم تنظيف المؤشر باستخدام GlobalFree ، فقد تم تخصيصه باستخدام
GlobalAlloc . لذلك ، لا يصدر مؤشرًا للذاكرة ، كما كان في الإصدار 16 بت ، ولكن رقم كائن به نوع HGLOBAL المُعلن عنه بشكل دلالة ، والذي يمكن تغذيته في دالة GlobalSize للحصول على حجم الكتلة المخصصة و GlobalLock لحظر قطعة من الذاكرة ، لكن للحصول على المؤشر الأصلي. بالمناسبة ، الحجر رقم 6 تجاه Microsoft لـ NIH malloc ومجاني ، والذي يوجد في المكتبة القياسية.
printf("%s\n", GlobalLock(answer.Check));
ولا يزال الحصول على انخفاض. حسنًا ، ما هو عرض GlobalSize؟ الصفر؟ غريب نوعا ما.
نتحقق من الوظائف الأخرى التي يجب أن تعطي أيضًا زلة - نرى نفس الصورة.
يتعلق الأمر برأسي فقط أنه يمكنني إنشاء قسيمة خاصة بي وفقًا للبيانات التي يمكن أن تقدمها وظيفة الدفع الأروع (نعم ، لدى سبيربنك وظائف تسمى card_authorize2..14 ، لن أضع حجرًا في ذلك):
struct auth_answer14 { auth_answer ans; char AuthCode[MAX_AUTHCODE]; char CardID[CARD_ID_LEN]; int ErrorCode; char TransDate[TRANSDATE_LEN]; int TransNumber; int SberOwnCard; char Hash[CARD_HASH_LEN]; char Track3[CARD_TRACK3_LEN]; DWORD RequestID; DWORD Department; char RRN[MAX_REFNUM]; DWORD CurrencyCode; char CardEntryMode; char CardName[MAX_CARD_NAME_LEN]; char AID[MAX_AID_ASCII_LEN]; char FullErrorText[MAX_FULL_ERROR_TEXT]; DWORD GoodsPrice; DWORD GoodsVolume; char GoodsCode[MAX_GOODS_CODE+1]; char GoodsName[MAX_GOODS_NAME]; }; PILOT_NT_API int card_authorize14( char *track2, struct auth_answer14 *auth_answer, struct payment_info_item *payinfo );
… , — .
:
: , , ; ; ; ; ; ; .
, , .
.
, «examples»
std::cout << "Authorization completion finished with code '" << result << "'" << std::endl; std::ofstream file(CHEQUE_FILENAME); file << argument.auth_answ.Check; file.close(); if (argument.auth_answ.Check) { std::cout << "Cheque saved to file " << CHEQUE_FILENAME << std::endl;
يعرض ببساطة النص الموجود على المؤشر. لكننا رأينا بالفعل أنه لا يعمل مثل هذا ... فقط في حالة ، سنقوم بتجميع مثالهم وتشغيله. المغادرة على السطر `file << argument.auth_answ.Check ؛` ، حسناً ، سبيربنك ، ضع حجر # 11 للحصول على أمثلة غير عاملة.7 صباحًا يمكنك بالفعل الكتابة إلى مطوري برنامج آخر تم كتابته في دلفي قبل عدة سنوات. نحصل على الجواب الذي يعمل كل شيء بالنسبة لهم. نحن نبحث عن أساس غلافهم والعثور على جيثب : TAuthAnswer = packed record TType: integer; Amount: UINT;
نوع بسيط لتحويل مؤشر دون أي استدعاءات وظيفة.نبدأ في الشك في الأرواح الشريرة.الفصل 17. اندلعت عاصفة رعدية
يبدأ الناس في العودة إلى المكتب ، ويومئون برؤوسهم متعاطفة. PO لا يبدو سعيدًا جدًا بمعرفة آخر الأخبار.هنا أذكر تفاصيل واحدة. عندما عرضنا حقول البنية رقم 14 لرؤية قيمها ، تم قطع بايت واحد من كل سطر. من ناحية ، من ناحية أخرىتحذير!في بنية auth_answer14 ، يكون اسم المنتج أقصر من حرف واحد في gate.dll TGoodsData. إصلاح هذا الخطأ كمعيار
ربما لا يزال متصلاً بـ ...تخمين فظيع على الدماغ مثل البرق. أعلن الهيكل كما typedef struct __attribute__((packed)) { int TType; unsigned long Amount; char RCode[3]; char AMessage[16]; int CType; char* Check; };
و ...لا شيء يتغير.لا يزال حجم = 0 ، لا يزال قفل = فارغة.ألم.الاضمحلال.لا مبالاة أنك تنظر بعينيك إلى شعاع مريح على السقف ، بحيث يمكنه تحمل الوزن. بعد العديد من الساعات غير المتوقفة من الترميز ودراسة الوثائق ، تطفو صفوف نحيلة من البايتات أمام أعيننا. ولكن ماذا لو قمنا بطباعة البايتات التي يتم إرجاعها بشكل عام؟ u32 i; for (i = 0; i < sizeof(answ); i++) { printf("%02x ", *((u8 *)&answ + i)); } printf("\n"); C:\banks\sber\sb_pilot>sb_pilot.exe 1 1000 01 00 00 00 e8 03 00 00 30 00 00 ce e4 ee e1 f0 e5 ed ee 00 00 00 00 00 00 00 00 02 00 00 00 f8 6c 7a 00 00
`30 00 00 م` - مما يعني أن سبيربنك لا يزال يستخدم الهياكل المعبأة. لكن لا توجد كلمة عن ذلك في الرؤوس. لذلك ، لا تعمل الأمثلة ، لذلك ، من المستحيل الحصول على مؤشر على النص في النهاية - لأنه تم كسره بسبب تحول 1 بايت. حجر ضخم وخشن نحو سبيربنك!ثم اشتعلت فارق بسيط من عيني عينك. 4 + 4 + 3 + 16 + 4 + 4 = 35. وهنا 36 بايت ، Obelix.إذا كان هناك 36 بايت ، فإن المترجم لا يزال محاذاة الهيكل. لذلك بين RCode و AMessage ، لا يزال يتم إدخال بايت إضافي. لكن لماذا؟ بعد كل شيء ، أشرنا `__packed__`!الفصل 18. رحلة العودة
, 2012 :
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 . GCC 8 ( 6 !), . workaround:
-mno-ms-bitfields
, :

! ! , - , .
, , , , GlobalSize/Lock .
19.
لتقليل عدد ifdefs للطبقة لـ sb_pilot ، كتبنا تطبيقًا منفصلاً يقلد إصدار linux sb_pilot تمامًا. وبالتالي ، ترك رمز الطبقة # 1 كما هو ، تاركًا شرطًا واحدًا فقط: #if defined(BXI_OS_GLX) #define GFJ_PILOT_EXECUTABLE "./sb_pilot" #elif defined(BXI_OS_WIN) #define GFJ_PILOT_EXECUTABLE "./sb_pilot.exe" #endif
نتائج المعركة:- سبيربنك: 12 الحجارة
- مايكروسوفت: 7 أحجار
- دول مجلس التعاون الخليجي: حجر واحد
الإنجاز والتذكر على لوحة القيادة لدينا: