Sberbank atau di sana dan kembali



BAB 1. Tamu yang tidak terduga


Semuanya berawal pada pagi yang naas itu ketika Manajer Proyek mengumumkan bahwa tenggat waktu pelaksanaan proyek harus dikurangi dengan cepat dan pasti satu bulan. Lebih tepatnya, proyek harus siap dalam 4 hari. Tidak, PO kami bukan binatang buas, dan sama sekali tidak terlihat seperti burung hantu (mungkin hanya sedikit seperti burung gagak), itu terjadi begitu saja. Ya, jika perlu, itu perlu, terutama karena tim (dan saya adalah pengembang terkemuka tim "C") dijanjikan sesuatu yang enak. Jam dan kalender adalah Kamis, 11:00, pada hari Senin, proyek harus siap.

Sebagai permulaan, apa yang kita lakukan sama sekali. Kami bergerak di bidang otomasi bioskop - pengontrolan peralatan otomatis dan jarak jauh, otomasi pemutaran film, pemantauan, panel video, dan sekarang juga terminal untuk penjualan tiket dan bar. Secara khusus, paragraf terakhir dikhususkan untuk artikel ini.

Proyek itu sendiri, yang harus diselesaikan sebelum Senin, adalah semacam lapisan antara server utama di Scala dan terminal pembayaran besi VeriFone VX 820 (pada kenyataannya, ada lebih banyak terminal, tetapi anggap saja sebagai contoh). Jelas bahwa tidak ada yang akan memberi kita transaksi melalui itu begitu saja, oleh karena itu utilitas dan perpustakaan Sberbank / Arcus dan UCS digunakan. Dengan demikian, skema kerja sebagai hasilnya harus sebagai berikut:



Secara lahiriah, ini terlihat seperti ini:



Juga, subsistem ini harus digunakan pada register kas standar yang semua orang lihat di bioskop mana pun di kasir.

Menurut tradisi internal, kami menyebut setiap proyek tim kami nama dari mitologi Nordik Lama, untuk subsistem ini nama Gefjon dipilih - nama dewi kesuburan dan kesuburan (nama yang baik untuk server pembayaran, bukan? Nah, legenda tentang banteng yang memotong pulau idealnya sesuai dengan arsitektur saat ini, memutuskan pekerjaan dengan peralatan dari bahasa tingkat tinggi).

Format pesan masuk dan keluar adalah server HTTP dengan beban JSON. Ini adalah kompromi optimal antara Scala, yang sulit untuk mengisolasi data biner dari aliran soket dan C, yang sulit untuk bangun untuk mentransfer objek melalui jaringan. Tidak banyak operasi yang mungkin perlu dilakukan pada: pembayaran, pembatalan, pengembalian, berbagai jenis laporan, membuka menu layanan dan ping. Tidak terlihat rumit. Karena ada tiga sistem perbankan (dan diharapkan penambahan keluarga), diputuskan untuk membagi proyek menjadi beberapa komponen:



Blok hijau adalah blok yang harus kita buat, blok biru adalah blok yang tidak bisa diubah dan yang disediakan bank.

Karena masalah utama muncul hanya dengan perangkat lunak dari Sberbank, artikel secara keseluruhan akan dikhususkan untuk perangkap, yang kami hitung dengan kapal kami.

BAB 2. Domba panggang



(foto: heaclub.ru)

... terlihat seperti ini. Kode prototipe itu, yang ditulis beberapa bulan lalu untuk memperjelas semua orang di tingkat yang lebih tinggi bahwa kita dapat bekerja dengan aplikasi perbankan, tampak sama.

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 

Jelas bahwa ini tidak cocok untuk versi Produksi, jadi pada dasarnya perlu untuk menulis semuanya lagi.

Setiap bank yang menyediakan perpustakaan untuk bekerja dengan terminal biasanya menyediakan dua opsi koneksi: melalui fungsi perpustakaan (.so / .dll) atau melalui utilitas siap pakai yang hanya perlu memberikan dua nilai - jenis operasi dan jumlah (bila diperlukan). Secara teori, tidak ada yang rumit, hanya sesuatu

 char buffer[100]; sprintf(buffer, "%d %d", atoi(argv[1]), atoi(argv[2])); system(buffer); 

Hasil operasi akan ditempatkan di file "e", dan slip-cek di file "p". Kirimkan saja file-file ini ke stdout dengan konversi ke JSON, sehingga server HTTP hanya mengirimkannya sebagai muatan tanpa memikirkan apa yang ada di sana.

Tetapi artikel ini tidak akan diterbitkan jika semuanya begitu sederhana.

BAB 4. Melintasi gunung dan di bawah gunung


Versi awal implementasi adalah panggilan aplikasi sederhana - server HTTP disebut pembungkus yang diperlukan dengan parameter terpadu (misalnya, laporan-X adalah 4), dan utilitas, misalnya gfj_pilot, meluncurkan sb_pilot dengan parameter yang diperlukan untuk operasi ini (misalnya, laporan-X adalah 9) . Kemudian utilitas pembungkus membaca hasil operasi dari e-file (misalnya, 2000 - "pembayaran ditolak, ulangi operasi") dan mengubahnya menjadi kesalahan universal (misalnya 3 - "Kesalahan membaca atau memproses kartu / akun, ulangi operasi"). Setelah itu, file "p" dikonversi ke base64 untuk menghindari pemformatan yang rusak dan dikirim bersama hasilnya ke stdout sebagai JSON.

Semua ini bekerja dengan sempurna sampai pada suatu saat kami diberitahu bahwa ...

... ini tidak berfungsi di Windows.



Yah, lebih tepatnya, Windows itu sendiri tidak memiliki masalah (kecuali bahwa slip dihasilkan dalam pengkodean Cp-1251, dan konsol bekerja di CP866). File "e" sama sekali tidak dibuat. Meluncurkan utilitas perbankan secara langsung:

 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> 

Memang, tidak ada file "e". Batu menuju Sberbank # 1. Kami sedang menulis surat kepada Sberbank (kami kemudian menerima jawaban bahwa seharusnya demikian), dan karena tidak ada waktu untuk korespondensi dan kami harus mulai sekarang, kami sedang mencari solusi untuk mendapatkan hasilnya.

 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 

Ya, hasilnya dapat diperoleh dari log sbkernel.log. Nyaman, ditambah tidak ada hash peta untuk kemudian mengacaukan "Terima kasih" dari Sberbank. Tidak bagus

Anda harus terhubung ke perpustakaan pilot_nt.dll dan mengimpor fungsi-fungsi darinya. Semuanya akan baik-baik saja, tapi ... Sebuah batu menuju Sberbank # 2: tidak ada perpustakaan seperti di Linux, Anda harus membuat dua aplikasi yang berbeda untuk platform yang berbeda - untuk linux, panggil utilitas sb_pilot (mirip dengan loadparm.exe, dengan cara batu # 3 untuk nama utilitas berbeda di bawah platform yang berbeda ), di bawah windows terhubung ke perpustakaan pilot_nt.dll.

BAB 5. Teka-teki dalam gelap


Pukul 19.00.

Sberbank adalah perusahaan besar, sebagian besar solusi perangkat lunak diproduksi sesuai dengan GOST dan dokumen formal. Kami masuk ke katalog yang disediakan Sberbank dengan perpustakaan:

 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 

Banyak hal bagus, tetapi kami hanya tertarik pada direktori untuk pengembang:

 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 

Banyak kertas bekas, untuk jaga-jaga, baca kembali pilot_nt, dari mana kita mempelajari yang berikut:
Tabel 1. OS sb_pilot yang didukung.
OSKapasitasNama modul
Windows32sb_pilot.exe
Linux32sb_pilot
Dos16sb_pilot.exe

Ternyata utilitas untuk windows masih harus disebut sb_pilot. Nah, batu menuju Sberbank # 4 untuk inkonsistensi dokumentasi sendiri.
Transfer hasil program.

Di akhir program, dua file teks terbentuk - file pertukaran dan file cek.

Yang pertama bernama e dan dimaksudkan untuk memberikan parameter operasi yang sempurna ke program panggilan. Baris pertama dalam file ini berisi kode hasil operasi, dan teks yang dipisahkan koma yang menjelaskan pesan teks. Kode 0 berarti pembayaran yang berhasil, nilai apa pun - penolakan atau ketidakmampuan untuk melakukan pembayaran.




Dengan malas kami melempar satu batu lagi dan mulai mempelajari dokumentasi untuk menghubungkan perpustakaan secara langsung.
Prosedur untuk memanggil fungsi perpustakaan

Ketika membayar (mengembalikan) pembelian dengan kartu kredit, program tunai harus memanggil fungsi card_authorize () dari perpustakaan Sberbank dengan mengisi bidang TType dan Jumlah dan menentukan nilai nol di bidang yang tersisa. Di akhir fungsi, Anda perlu menganalisis bidang RCode. Jika berisi nilai "0" atau "00", otorisasi dianggap berhasil diselesaikan, atau ditolak. Selain itu, Anda harus memeriksa nilai bidang Periksa.

Jika bukan NULL, itu harus dikirim untuk mencetak (dalam mode non-fiskal) dan kemudian
hapus dengan memanggil fungsi GlobalFree (). Saat menutup shift, program kas harus memanggil fungsi close_day () dari perpustakaan Sberbank dengan mengisi bidang TType = 7 dan menentukan nilai nol di bidang yang tersisa. Di akhir fungsi, periksa nilai bidang Periksa.

Jika bidang Periksa bukan NULL, itu harus dikirim untuk mencetak (dalam mode non-fiskal) dan kemudian dihapus dengan memanggil fungsi GlobaFree ().
Kedengarannya mudah, bahkan file header disediakan. Nah, pasang, kompilasi dan ...

 $ 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; /**< [in, out]                            .   . ::auth_answer */ ^ pilot_nt.h:544:3: error: unknown type name 'auth_answer' auth_answer ans; /**< [in, out]                            .   . ::auth_answer */ ^ pilot_nt.h:567:3: error: unknown type name 'auth_answer' auth_answer ans; /**< [in, out]                            .   . ::auth_answer */ ^ pilot_nt.h:590:3: error: unknown type name 'auth_answer' auth_answer ans; /**< [in, out]                            .   . ::auth_answer */ ^ pilot_nt.h:627:3: error: unknown type name 'auth_answer' auth_answer ans; /**< [in, out]                            .   . ::auth_answer */ ^ pilot_nt.h:668:3: error: unknown type name 'auth_answer' auth_answer ans; /**< [in, out]                            .   . ::auth_answer */ 

Ummm ... apa? Buka 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]     */ }; 

Segera, tanpa melihat batu untuk komentar dalam bahasa Rusia di CP1251 coding.

Nah, batu paling serius: pengembang C ++ tersayang. Jika Anda menulis extern "C", ini berarti bahwa kode di dalam blok harus dikompilasi oleh kompiler C. Jika Anda TIDAK membuat `typedef` dari suatu struktur, maka setiap kali Anda menyebutkannya sebagai referensi jenis, Anda harus menulis kata kunci` struct`.

Tambal file untuk pengembang, gantikan kata `struct` di mana pun dibutuhkan. Menautkan ke perpustakaan `pilot_nt.dll`. Kemenangan, bukan? Kami meluncurkan aplikasi kami.

BAB 6. Dari Api ke Api


Nah, Anda mengerti, kan? Aplikasi hanya macet. Sampai ke utama. Renungkan, tambahkan analog NIH dari fungsi errno untuk windows: GetLastError (batu # 3 menuju Microsoft, dua yang pertama adalah untuk penyandian).

 C:\banks\sber\WIN>sb_pilot.exe 1 1000 E: !g_sblibrary (0xc0000096) 

0xc0000096? Tidakkah GetLastError mengembalikan kode kesalahan yang memadai?
Untuk daftar kode kesalahan lengkap yang disediakan oleh sistem operasi, lihat Kode Kesalahan Sistem.
Ya, buka artikel di sini :
Topik-topik berikut menyediakan daftar kode kesalahan sistem. Nilai-nilai ini didefinisikan dalam file header WinError.h.

  • Kode Kesalahan Sistem (0-499) (0x0-0x1f3)
  • Kode Kesalahan Sistem (500-999) (0x1f4-0x3e7)
  • Kode Kesalahan Sistem (1000-1299) (0x3e8-0x513)
  • Kode Kesalahan Sistem (1300-1699) (0x514-0x6a3)
  • Kode Kesalahan Sistem (1700-3999) (0x6a4-0xf9f)
  • Kode Kesalahan Sistem (4000-5999) (0xfa0-0x176f)
  • Kode Kesalahan Sistem (6000-8199) (0x1770-0x2007)
  • Kode Kesalahan Sistem (8200-8999) (0x2008-0x2327)
  • Kode Kesalahan Sistem (9000-11999) (0x2328-0x2edf)
  • Kode Kesalahan Sistem (12000-15999) (0x2ee0-0x3e7f)
Oke, kami mendapat kesalahan tidak berdokumen, kami melempar batu dan membuka google mahatahu:


Inti dari kesalahan adalah bahwa beberapa subrutin menggunakan salah satu instruksi

  • _inp ()
  • _inpw ()
  • _inpd ()
  • _outp ()
  • _outpw ()
  • _outpd ()

Penggunaan yang dilarang di bawah inti NT, karena mereka mencoba untuk bekerja dengan port paralel secara langsung. Rupanya, kode ini disebut di initializer perpustakaan, yaitu perpustakaan saat startup ingin polling port untuk perangkat, tetapi kernel NT membutuhkan kerja melalui driver.

Situasi tanpa harapan?

BAB 8. Laba-laba dan lalat


10 malam Untuk berjaga-jaga, muncul ide untuk memverifikasi bahwa ini bukan karena kami menggunakan cross-compiling dengan Linux menggunakan mingw. Pada saat yang sama, kami memahami bahwa Sberbank hanya memberikan aplikasi 32-bit, jadi itu tidak akan berfungsi dengan aplikasi 64-bit, oke, tapi tetap kami akan meluncurkan batu ke arah Sberbank untuk versi 32-satunya pada tahun 2019.

Diberikan : diinstal di virtualbox windows 7;
Diperlukan : Instal Visual Studio dan salin MVP.

Kami pergi ke situs web Microsoft, mengunduh Visual Studio 2017. Kami mengambil lisensi komunitas, karena kami mengambilnya untuk verifikasi, untuk bisnis lisensi akan dibeli jika lepas landas.
Unduh beberapa ratus megabyte dan ...

Kami melihat bahwa versi OS kami (Windows 7) tidak didukung.

Ok, kita pergi ke semua jenis situs cabul, kami mencari Visual Studio 2008, unduh beberapa ratus megabyte lagi dan ...

Kami mendapatkan file iso.

Oke, mari kita coba menginstal Daemon Tools 10 (karena ini adalah versi yang ditawarkan situs) untuk memasukkan disk virtual ini.

Jalankan binar yang diunduh. Misfire, membutuhkan .NET Framework 4.5, unduh, instal.
Kami mulai binar yang diunduh, instalasi telah dimulai, bootloader mengatakan bahwa ia perlu 4.5.2, unduh, instal.
Kami mulai binar yang diunduh, instalasi telah dimulai, bootloader mengatakan bahwa itu tidak akan pergi ke mana pun sampai kami menginstal pembaruan keamanan KB3033929, unduh, instal.

Dan kami mendapat tamparan di wajah dari Microsoft sebagai pesan:



Kami dengan keras melemparkan batu yang sangat tajam ke Microsoft, mengunduh Daemon Tools tua dari torrents, berhasil membongkar Visual Studio, menginstal, akhirnya (00:00) mengkompilasi MVP, kami mendapatkan kesalahan yang sama. Ya, ada versi yang bagus, tetapi tidak tumbuh bersama.

BAB 11. Di ambang pintu


Kami sedang menulis kepada programmer kedua, yang saat ini dengan mendesak menyelesaikan server dan prosedur pendaftaran. Dia ingat ada repositori git yang menghubungkan ke perpustakaan ini di NT dan bekerja dengannya.

Mencurigai melihat repositori, mengunduhnya, kompilasi dan menjalankannya. Itu bekerja.



Kami melihat kode lebih curiga. Kode identik, kecuali ditulis dalam C ++ dan bukan C.
Kami memahami bahwa bahasa tidak ada hubungannya dengan itu. Kami melihat perpustakaan Sberbank, yang menarik kode.
Kami melihat komit terakhir.

Dan di sini kita menunggu kejutan lain.

Ternyata versi pustaka Sberbank mungkin berbeda. Komit terakhir meningkatkan versi dari 23 menjadi 27. Salin versi dari gita ke komputer uji Anda - BEKERJA!

Kami memeriksa semua arsip yang dikirim oleh Sberbank, membandingkan versi dan membangun tablet:
VersiBekerja
26.0.15 - Dasartidak
27.4.12 - Dari repositoriiya
23.0.13 - Dari repositoriiya
29.0.9 - Terbaru dari Satiya
23.0.13 - Dengan tambalan untuk sistem Cryptoriya

Hebat, sekarang mari kita sembuh. Pada sistem yang harganya 26, tingkatkan ke 29 atau 27 dan semuanya akan berjalan.
Kami melempar batu # 9 ke arah Sberbank karena melanggar perilaku pada sistem NT.

BAB 12. Apa yang menanti mereka di dalam


File e tidak cukup? Tidak masalah, kami mengambil judul yang ditambal, tautan dinamis ke perpustakaan untuk mengembalikan kesalahan dengan benar, menulis kode yang hanya menulis kode pengembalian dari fungsi ke file "e", sebut saja biner sb_pilot.exe dan ...

Untuk bekerja, itu berfungsi.

Itu hanya versi untuk sistem "Cryptor" tidak membuat file "p".

Kami melihat dengan sedih darah yang menetes di buku-buku jari dan lekuk di dinding.

Sebagai permulaan, apa itu sistem Cryptor.

Cryptera adalah perusahaan Denmark yang memproduksi peralatan enkripsi / peralatan keamanan / kunci, dll. Saya pikir Anda semua melihat salah satu salinan dari produk mereka:



Jadi, Sberbank menggunakan modul crypto mereka untuk pinpads dan merilis pustaka "tambalan" khusus, di mana, seperti yang sudah kita pahami, file "p" tidak dibuat. Kami menulis kepada Sberbank tentang ini dan dalam beberapa hari kami akan mendapatkan jawaban bahwa "di bawah sistem asli, file" p "akan dibuat, tetapi di bawah ditambal ke Cryptor - no. Kami akan memberi mereka batu nomor 10 dalam beberapa hari, karena Anda harus bekerja sekarang.

Untungnya atau sayangnya, fungsi yang kami gunakan untuk melakukan operasi mengembalikan struktur yang telah disebutkan:

 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    */ }; 

Oh, baiklah, cek sudah ada di sana, kita dapat menyimpannya sendiri atau segera mencetaknya di JSON ...

 printf("%s\n", answer.Check); 

Dan kami mendapatkan aplikasi mogok karena akses ke pointer tidak valid.

BAB 14. Api dan air


Jam 4 pagi Kami melakukan Seth Bandha Sarvangasana untuk menenangkan diri, dan dengan cermat membaca manual:
Gambar cek, harus dibebaskan oleh GlobalFree di program panggilan
Apa yang ini berikan pada kita? Banyak. Pertama, karena pointer perlu dibersihkan menggunakan GlobalFree, itu di-salocated menggunakan GlobalAlloc . Oleh karena itu, ia tidak mengeluarkan pointer ke memori, seperti pada versi 16-bit, tetapi nomor objek dengan tipe HGLOBAL yang dideklarasi semantik, yang dapat dimasukkan dalam fungsi GlobalSize untuk mendapatkan ukuran blok yang dialokasikan dan GlobalLock untuk memblokir sepotong memori, tetapi mendapatkan pointer asli. By the way, batu # 6 menuju Microsoft untuk NIH malloc dan gratis, yang ada di perpustakaan standar.

 printf("%s\n", GlobalLock(answer.Check)); 

Dan masih mendapatkan setetes. Oke, apa yang ditampilkan GlobalSize? Nol? Entah bagaimana aneh.

Kami memeriksa fungsi lain yang juga harus memberikan slip - kami melihat gambar yang sama.

Hanya sampai di kepala saya bahwa saya dapat membuat slip sendiri berdasarkan data yang dapat diberikan fungsi pembayaran paling keren (ya, Sberbank memiliki fungsi yang disebut card_authorize2..14, saya tidak akan melempar batu untuk itu):

 struct auth_answer14 { auth_answer ans; /**< [in, out]   . . ::auth_answer */ char AuthCode[MAX_AUTHCODE]; /**< [out]  . 7 . */ char CardID[CARD_ID_LEN]; /**< [out]  . 25 .     ,   6   4,    '*'.*/ int ErrorCode; /**< [out]  . */ char TransDate[TRANSDATE_LEN]; /**< [out]     */ int TransNumber; /**< [out]    . , .    */ int SberOwnCard; /**< [out]     */ char Hash[CARD_HASH_LEN]; /**< [in, out]  SHA1   ,   ASCII     . 40 .*/ char Track3[CARD_TRACK3_LEN]; /**< [out]   */ DWORD RequestID; /**< [in,out]   .  PCI DSS .*/ DWORD Department; /**< [in]     0  14-, .      0xFFFFFFFF,          .        ,      4191. */ char RRN[MAX_REFNUM]; /**< [in,out]   ,  .    ,     .   12-  .       (   pilot_nt.dll),     –  (     ;     ,   ).*/ DWORD CurrencyCode; /**< [in]    (810, 643, 840, 978  ..) */ char CardEntryMode; /**< [out]    ('D'-., 'M'- , 'C'-, 'E'- EMV, 'R'- magstripe, 'F'-fallback)*/ char CardName[MAX_CARD_NAME_LEN]; /**< [out]    */ char AID[MAX_AID_ASCII_LEN]; /**< [out] Application ID   (   ASCIIZ-)*/ char FullErrorText[MAX_FULL_ERROR_TEXT]; /**< [out]     */ DWORD GoodsPrice; /**< [in]    ,  (34.99->3499)*/ DWORD GoodsVolume; /**< [in]  ,  .  (30.234->30234)*/ char GoodsCode[MAX_GOODS_CODE+1]; /**< [in]     .*/ char GoodsName[MAX_GOODS_NAME]; /**< [in]     . !   auth_answer14         gate.dll TGoodsData.     */ }; /** @brief     * @param[in] track2      .  NULL,     . * @param[in,out] auth_answer . ::auth_answer14 * @param[in,out] payinfo     * @return int  . */ 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; //GlobaFree(argument.auth_answ.Check); } 

, . , … . `file << argument.auth_answ.Check;`, , , #11 .

7:00. , Delphi. , . github :

 TAuthAnswer = packed record TType: integer; Amount: UINT; // IN     Rcode: array [0 .. 2] of AnsiChar; AMessage: array [0 .. 15] of AnsiChar; CType: integer; Check: PAnsiChar; end; Result := Func(nil, @FAuthAnswer); FLastError := Result; FCheque := PAnsiChar(FAuthAnswer.Check); 

- .

.

17.


, . PO .

. #14 . ,
Perhatian! auth_answer14 gate.dll TGoodsData.
…

.

 typedef struct __attribute__((packed)) { int TType; /**< [in]  .  ::OpetationTypes */ unsigned long Amount; /**< [in]    */ char RCode[3]; /**< [out]    */ char AMessage[16]; /**< [out]    */ int CType; /**< [in,out]   */ char* Check; /**< [out]  ,   GlobalFree    */ }; 

…

.

Size = 0, Lock = NULL.

.

.

, , . - . , ?

  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 ce` β€” , Packed . . , β€” - 1 . !

. 4 + 4 + 3 + 16 + 4 + 4 = 35. 36 , .

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.


ifdef' 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
  • GCC: 1

- :

Source: https://habr.com/ru/post/id451188/


All Articles