2 poin oleh GN⁺ 2023-09-05 | 1 komentar | Bagikan ke WhatsApp
  • Untuk mengubah konten teks dalam PDF tanpa alat PDF komersial, Anda perlu mengekstrak stream yang terkompresi, menelusuri encoding per font, lalu mengganti teks asli dan teks pengganti dengan cara yang sama
  • Banyak PDF menyimpan teks dokumen sebenarnya bukan sebagai plaintext, melainkan sebagai stream terkompresi dan string yang tampak seperti heksadesimal; qpdf --qdf --object-streams=disable dapat mengekstraknya ke bentuk yang lebih mendekati bisa diedit
  • Blok teks terdiri dari perintah PDF seperti BT, Tf, Td, Tj, ET, dan nilai seperti <002a004800570003003600480057> Tj belum tentu merupakan code point Unicode sederhana
  • Jika PDF menyertakan pemetaan ToUnicode per font, Anda bisa memakai pdffonts untuk memeriksa apakah emb dan uni bernilai yes, lalu mengikuti referensi seperti /ToUnicode 19 0 R untuk menemukan tabel encoding
  • Karena kompleksitas standar PDF, metode ini sulit digeneralisasi ke semua file, tetapi pada PDF tertentu Anda dapat menemukan encoding teks asli dan mengganti teks dengan find-and-replace

Mengekstrak Stream Teks PDF yang Terkompresi

  • Jika PDF dibuka dengan editor teks, sebagian strukturnya dapat terbaca, tetapi teks dokumen sebenarnya mungkin tidak terlihat
  • Banyak PDF menyimpan data teks dalam bentuk terkompresi
  • Anda dapat mengekstrak stream teks terkompresi dengan qpdf untuk memeriksanya
    • Di Mac tersedia formula homebrew
    • Di distribusi Linux, alat terkait juga tersedia
qpdf --qdf --object-streams=disable in.pdf out.pdf
  • Setelah diedit, stream dapat dikompresi kembali
qpdf out-edited.pdf out-recompressed.pdf
  • Perintah kompresi ulang menghasilkan error, tetapi PDF hasilnya tetap dapat dibaca di Preview

Mencari Teks di Dalam Perintah PDF

  • Setelah diekstrak pun, teks masih berada di dalam blok perintah PDF
  • Blok teks dasar memiliki bentuk seperti berikut
BT
  /Font_0 12 Tf
  288 720 Td
  <002a004800570003003600480057> Tj
ET
  • Berdasarkan PDF Reference, blok ini menjalankan operasi berikut secara berurutan
    • Memulai objek teks
    • Mengatur font dan ukuran yang akan digunakan
    • Menentukan posisi awal pada halaman
    • Menggambar glyph string di posisi tersebut
    • Mengakhiri objek teks

Mengapa Teks Tidak Langsung Terbaca

  • Nilai seperti <002a004800570003003600480057> terlihat seperti string heksadesimal, tetapi belum tentu merupakan daftar code point Unicode sederhana
  • PDF memiliki banyak cara untuk menentukan encoding, dan dapat menyertakan encoding kustom di dalam file
  • Encoding semacam ini pada umumnya dapat dipetakan ke code point Unicode
  • Prosedur ini mengasumsikan PDF yang sedang dikerjakan menyertakan encoding tertanam
    • Cara menangani kasus lain tidak dibahas

Memeriksa Font dan Pemetaan Unicode

  • Encoding teks PDF terkait dengan font tertentu
  • pdffonts menampilkan informasi tentang font dan encoding di dalam PDF
$ pdffonts sample.pdf
name                                 type              emb sub uni prob object ID
------------------------------------ ----------------- --- --- --- ---- ---------
CLDQZB+TrebuchetMS,Bold              CID TrueType      yes yes yes           9  0
YQBAIZ+TrebuchetMS                   CID TrueType      yes yes yes          10  0
  • Field yang perlu diperiksa di sini adalah sebagai berikut
    • emb: berarti font tertanam di dalam PDF
    • uni: berarti ada pemetaan Unicode
  • Jika kedua nilainya yes, ada kemungkinan Anda dapat menemukan pemetaan yang diperlukan
  • Identifier font seperti /Font_0 dalam contoh dapat berkorespondensi dengan nama font pada output pdffonts, bergantung pada kasusnya
    • Pada kasus tersebut, /Font_0 menunjuk ke CLDQZB+TrebuchetMS,Bold

Menelusuri Tabel Pemetaan ToUnicode

  • Setelah menemukan nama lengkap font yang digunakan pada teks, cari nama tersebut di dalam PDF
  • Di lokasi tertentu, Anda dapat menemukan referensi seperti berikut
/ToUnicode 19 0 R
  • Nilai ini menunjuk ke ID objek tabel encoding
  • Setelah itu, dengan mencari 19 0 obj, tabel tersebut dapat ditemukan

Mengganti Teks Menggunakan Tabel Encoding

  • Bagian inti tabel pemetaan dapat berbentuk seperti berikut
38 beginbfrange^M
<0036><0036><0053>^M
<0057><0057><0074>^M
<0044><0044><0061>^M
<0048><0048><0065>^M
<0050><0050><006D>^M
...
  • Contoh ini memetakan rentang titik encoding kustom ke titik Unicode
    • Di sini rentangnya hanya satu karakter
    • 0036 dipetakan ke titik Unicode 0053
  • Jika format tabelnya berbeda, Anda dapat merujuk ke tutorial file pemetaan ToUnicode
  • Untuk konversi otomatis, tabel diubah menjadi dictionary dengan Python dan fungsi encoding/decoding sederhana ditulis
  • Alur penggantian akhirnya adalah sebagai berikut
    • Periksa nilai encoding kustom dari teks lama yang ingin diganti
    • Encoding teks pengganti dengan cara yang sama ke encoding kustom
    • Ganti nilai lama di PDF dengan find-and-replace

1 komentar

 
GN⁺ 2023-09-05
Opini Hacker News
  • Spesifikasi PDF cukup kasar. Trivia favorit saya belakangan ini adalah bahwa saat merender elemen yang saling tumpang tindih, PDF mendukung semua mode blend layer Photoshop
    Favorit kedua saya: konten yang ditambahkan di belakang bisa mengubah konten sebelumnya, jadi semua versi berbeda yang direpresentasikan dalam satu berkas harus diperiksa secara forensik
    Ini juga contoh yang menunjukkan kehampaan DRM. Di spesifikasi ada enkripsi berbasis kata sandi, bisa ada kata sandi “owner” dan “user” yang terpisah, serta bit field seperti “dilarang mencetak” dan “dilarang menyalin teks”. Namun agar dokumen bisa dibaca, pada akhirnya ia harus didekripsi, jadi jika Anda membuka PDF terenkripsi dengan kata sandi “user” di alat yang tidak patuh, lalu menyimpannya sebagai versi yang tidak terenkripsi, Anda mendapatkan salinan ekuivalen yang bisa diedit
    [1] Bagian “More than just transparency” dari https://blog.adobe.com/en/publish/2022/01/31/20-years-of-tra...
    [2] https://blog.didierstevens.com/2008/05/07/solving-a-little-p...
    [3] Halaman 61 dari https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
    [4] Misalnya skrip yang memakai pustaka pypdf

    • Dalam konteks bahwa awalnya itu adalah format proprietari, tidak dibuka luas untuk semua orang, dan dibuat pada era ketika enkripsi sangat dikontrol oleh hukum ekspor, security through obscurity semacam itu sangat umum
      Salah satu tutorial cracking terkenal saat itu menghapus DRM dari reader resmi dengan menambal fungsi yang memeriksa izin
    • Caranya: https://www.cyberciti.biz/faq/removing-password-from-pdf-on-...
    • Bukankah mode blend yang didukung itu hanya mode komposit Porter-Duff? Mungkin terlihat berlebihan, tetapi itu sangat cocok dengan apa yang disediakan pipeline rendering lain, dan cukup membantu mengurangi beban kerja dalam membuat PDF
    • Kalau menggali field izin, Anda akan masuk ke lubang kelinci tentang bagaimana sebagian pembuat PDF tidak mematuhi spesifikasi, dan berbagai penanganan bypass yang mungkin ada atau tidak ada di masing-masing reader atau pustaka PDF
    • Agar adil, jika ingin mencegah penyalinan teks, cara termudah adalah menghilangkan pemetaan ToUnicode pada font. Dengan begitu, orang harus membuatnya ulang secara manual
  • Topik ini muncul secara berkala; kebanyakan orang menganggap PDF sebagai format biner yang sulit ditembus, padahal sebenarnya tidak demikian
    PDF adalah graf objek dengan berbagai tipe, dan tipenya sendiri dijelaskan dengan baik dalam spesifikasi resmi. Saya punya selera menyiksa diri untuk membacanya demi hiburan
    Yang selalu saya sarankan adalah, seperti penulis, mengonversi PDF menjadi versi tanpa data terkompresi. Alat favorit saya adalah mutool, dan Anda bisa memakai mutool clean -d in.pdf out.pdf. Setelah itu, jika Anda mengubek-ubeknya, Anda akan terkejut karena lebih banyak bagian yang bisa diikuti daripada yang diduga
    Artikel itu melewatkan tahap melihat objek halaman dan memeriksa resource. Di sanalah nama font yang dipakai dalam content stream dihubungkan dengan sub-objek sebenarnya
    Bagian penting lain yang terlewat adalah bahwa sebagian besar font dimasukkan ke dalam PDF sebagai subset. Hanya glif yang diperlukan yang dipertahankan di font. Re-encoding biasanya tampaknya terjadi di sini, dan ToUnicode dipertahankan agar penyalinan teks atau pencarian PDF bisa dilakukan. Itu hal yang bagus bagi pengguna, dan menurut pengalaman saya umumnya ada serta cukup benar

    • Kalau “membacanya demi hiburan”, itu lebih dekat ke masokis daripada sadis. Kalau ikut menulis spesifikasinya atau membuat orang lain membacanya, barulah sadis
    • Sayang sekali Adobe merancang format yang begitu sulit ditangani, sampai orang-orang terkejut ketika seseorang berhasil melakukan sesuatu yang seharusnya menjadi pekerjaan dasar
      Sejak awal, filosofi desain untuk membuat format read-only itu sendiri sudah keliru. Bukankah fungsi pertama yang akan diminta orang sudah jelas?
    • Kalau menikmati rasa sakit pada diri sendiri, itu masokis; kalau suka memberikan rasa sakit pada orang lain, itu sadis. Sepertinya orang ini berusaha membantu orang lain, jadi lebih dekat ke yang pertama. Saya menghargai saran mutool itu
    • Saya banyak bergantung pada Amazon Textract untuk parsing PDF
      Saya penasaran apakah ada wawasan lain tentang cara menanganinya dengan baik secara native tanpa penyedia cloud. Terutama saat menangani tabel
  • Bisa dilakukan seperti ini:
    Konversi ke PostScript a.ps dengan pdf2ps a.pdf
    Edit PostScript langsung dengan vim a.ps
    Konversi kembali ke PDF dengan ps2pdf a.ps
    PDF kompleks yang berisi JavaScript bawaan atau animasi kadang tidak berfungsi dengan benar setelah proses bolak-balik ini. Meski begitu, untuk dokumen biasa, cara ini bekerja cukup baik. Menghapus watermark serta mengubah kata dan angka mudah dilakukan, sedangkan mengubah spasi/jarak lebih sulit. Tentu saja, Anda perlu sedikit banyak memahami PostScript

    • Di perusahaan pemrosesan surat tempat saya dulu bekerja, sebagian pekerjaan persiapan cetak dilakukan kira-kira seperti ini. Biasanya kami membuat dokumen siap cetak dengan alat yang semestinya, tetapi sesekali pelanggan merasa lebih tahu lalu mengirim PDF, yang umumnya membutuhkan lebih banyak pekerjaan dan lebih berisiko terjadi kesalahan
      Walaupun output-nya sudah benar, kami tetap perlu menyusun ulang halaman, menerapkan barcode untuk pemrosesan mesin surat dan penyortiran pos, serta membuat laporan. Biasanya kami mengeruk teks dari halaman dengan Perl dan alat lain untuk mendapatkan alamat, dan PS umumnya jauh lebih mudah daripada PDF, tetapi ada juga kasus yang sangat rapuh, misalnya ketika PDF “aman” tidak memiliki pemetaan glyph yang benar
      Dalam kasus terburuk, pelanggan mengirim PDF dokumen tunggal, dan ketika digabungkan, font subset pada output membengkak drastis hingga memenuhi memori printer dan membuatnya mati. Saat saya berhenti dari pekerjaan itu pun, rasanya belum ada alat berguna untuk menyatukan dan menggabungkan font subset yang berasal dari font sumber yang sama. Seharusnya itu mungkin dan akan sangat berguna, tetapi saya tidak punya waktu atau pengetahuan untuk menyelidikinya
    • Jika PDF bisa berisi JavaScript dan animasi, apa yang mencegah kita membuat frontend di dalamnya? Saya penasaran sejauh mana batas hal-hal yang bisa dilakukan dengan PDF
      Sejujurnya, tampaknya satu-satunya pihak yang diuntungkan oleh kompleksitas PDF hanyalah pembuat malware
  • Sepertinya ada poin penting yang terlewat. Di akhir PDF ada tabel yang menyimpan offset byte berbagai objek di dalam file, yaitu tabel referensi silang
    Jika isi file diubah, biasanya offset-offset ini berubah dan file menjadi rusak. Tulisan itu tampaknya hanya peduli pada mengganti satu angka dengan angka lain, sehingga posisinya mungkin tidak berubah
    Namun secara umum, jika Anda menambah, menghapus, atau mengubah sesuatu di tengah file, tabel xref harus dihitung ulang, sehingga memakai library jauh lebih mudah daripada mengedit teks secara langsung

    • Itulah sebabnya file didekode dengan qpdf lalu dienkode lagi setelahnya. Dengan begitu qpdf menangani bagian itu
      qpdf tampaknya merekonstruksi struktur PDF asli dan mencoba mempertahankan nomor objek apa adanya, tetapi offset dihitung ulang sepenuhnya
    • Menurut saya itu bagian paling aneh dari spesifikasi PDF. Biner dan teks bercampur, dan offset byte ditentukan sebagai teks
      Kalau para pembuatnya suatu hari bercerita, saya ingin membaca mengapa formatnya menjadi seperti itu. Rasanya awalnya dimaksudkan sebagai format teks sepenuhnya, lalu belakangan mereka menilai biner lebih efisien. Namun keharusan membuat panjang entri tabel xref tetap juga agak aneh jika dikaitkan dengan asumsi itu
    • Berdasarkan pengalaman saya, cara termudah adalah membiarkan tabel xref rusak lalu menjalankan sesuatu seperti mutool clean untuk memperbaikinya. Karena dapat diturunkan sepenuhnya dari kontennya, ini aman
    • Ini cukup mirip dengan mengedit biner terkompilasi
      Selama panjangnya dipertahankan, biner bisa diubah sesuka hati
      Ada sebuah perangkat lunak yang dulu saya pakai yang melakukan autentikasi ke server, tetapi semua pemrosesan berlangsung di sisi klien. Klien mengeksekusi SQL langsung ke server, dan server hanya memeriksa apakah klien ini melampaui jumlah lisensi yang dibeli
      Saya bisa menjalankannya di disassembler untuk menemukan bagian pemeriksaan, mengubah bagian itu langsung menjadi JMP, lalu mengisi ruang tersisa dengan NOP
  • Sepertinya ada langkah penting yang terlewat saat memakai mode --qdf milik qpdf. Setelah selesai mengedit, file perlu dilewatkan ke utilitas fix-pdf untuk menghitung ulang semua offset objek dan membangun ulang tabel referensi silang di akhir file. Pengecualiannya adalah jika Anda hanya mengganti di tempat tanpa menambah atau menghapus byte
    Tiga fakta menarik teratas tentang PDF adalah sebagai berikut

    1. Dokumen PDF biasanya berupa file biner 8-bit, tetapi dengan filter ASCII85 Anda bisa membuat PDF teks polos UTF-8 yang valid, termasuk gambar
    2. PDF mengizinkan sangat banyak fitur aneh, seperti objek 3D, JavaScript, video di dalam objek Flash tertanam, anotasi tak terlihat, dan sebagainya. PDF/A adalah subset yang jauh lebih waras dan aman
    3. Spesifikasi PDF memungkinkan widget, misalnya kontrol formulir, ditulis sebagai rich text yang merupakan subset XHTML dan CSS. Namun fitur ini sangat jarang didukung di luar Adobe Reader resmi
      [0] Contoh: https://lab6.com/2
    • Setelah selesai mengedit, cukup lewatkan ke qpdf tanpa parameter seperti dijelaskan di bagian awal tulisan. Itu akan mengompresi ulang data dan membangun ulang tabel xref. Tidak perlu alat lain
  • Jika ingin terus mempelajari perjalanan PDF ini lebih lanjut, Anda bisa membaca dokumen pembedahan file yang baru-baru ini saya susun:
    https://pdfsyntax.dev/introduction_pdf_syntax.html

  • Hal yang sering dilewatkan orang tentang PDF adalah bahwa dalam beberapa hal PDF lebih dekat ke format gambar daripada dokumen Word. Dalam penyuntingan dokumen, dokumen Word, PDF, dan gambar itu seperti proyek DAW, MIDI, dan MP3 dalam musik; mirip juga dengan kode sumber Java, bytecode JVM, dan bahasa mesin x86 murni dalam perangkat lunak
    Tujuan utama file PDF adalah memberi tahu secara sepenuhnya jelas apa yang harus ditampilkan atau dicetak, dengan jumlah byte yang jauh lebih sedikit daripada gambar sebenarnya. Dengan memanfaatkan fakta bahwa pembuat dokumen mengetahui pola struktur dokumen, jika direpresentasikan dengan benar, hasilnya bisa terkompresi jauh lebih baik daripada algoritme kompresi gambar nyata. Misalnya, jika bisa mengakses font yang sebenarnya, lebih baik mengatakan “letakkan karakter-karakter ini di koordinat ini dengan jarak ini” daripada memasukkan setiap kemunculan huruf sebagai bagian dari gambar dan berharap algoritme kompresi mengurangi pengulangan dengan sendirinya. Karakter mana yang termasuk ke kata mana, bahkan codepoint Unicode mana yang sesuai dengan glyph font mana, pada dasarnya tidak penting jika tujuannya hanya menyampaikan citra dokumen secara efisien
    Untuk dokumen yang dapat diedit, bukan hanya tampilan, tetapi struktur makna kontennya menjadi jauh lebih penting. Penting apakah jeda tertentu dalam teks adalah beberapa spasi, kolom berikutnya dalam tabel, atau tata letak halaman yang aneh karena gambar. Penting juga apakah teks di bagian bawah setiap halaman dimasukkan berkali-kali oleh penulis, atau dimasukkan sekali lalu ditetapkan sebagai footer. Jika menambahkan paragraf baru harus mengubah tata letak halaman, penting untuk mengetahui bahwa paragraf terakhir di halaman ini adalah catatan kaki sehingga tidak boleh berpindah ke halaman berikutnya. Yang penting adalah judul bagian yang berpindah ke halaman lain harus membuat daftar isi diperbarui otomatis, bukan sekadar teks yang diketik manual oleh penulis
    Dari sudut pandang printer atau layar, semua itu tidak ada relevansinya. Mereka cukup mencetak atau menampilkan sesuai instruksi. Dalam PDF, catatan kaki, judul bagian, footer, dan daftar isi tidak perlu bersifat khusus; bisa saja hanya teks berformat tanpa makna. Karena itu, jika PDF digunakan untuk tujuan selain menampilkan atau mencetak, hasilnya tidak bisa 100% akurat. Tentu ada upaya untuk menambal kekurangan ini, dan program pembuat PDF bebas memasukkan metadata yang diinginkan, tetapi itu tidak wajib
    Ini mungkin bukan model mental yang dimaksudkan oleh para pembuat PDF, tetapi sudut pandang ini berguna untuk memahami mengapa PDF berbentuk seperti itu

    • Tujuan awal PDF adalah membuat salinan dengan fidelitas cetak yang portabel. WYSIWYG yang sesungguhnya. File PDF harus terlihat sama baik dikirim ke printer laser, linotype, maupun layar
      Jika dicetak dengan printer PostScript, tampilannya persis sama, dan dengan font Type 1 kadang bahkan lebih baik
  • Orang yang ingin melakukan ini melewatkan inti dari PDF. PDF adalah format deskripsi halaman, jadi ia hanya merepresentasikan jejak tampilan di atas halaman, bukan struktur dokumen
    Jangan mencoba mengedit PDF; editlah dokumen asli yang menghasilkan PDF itu

    • Kalau orang berhenti mengirim PDF yang ingin saya edit, saya juga akan berhenti mengedit PDF
      Entah bagaimana, mengirim dokumen yang memang dibuat untuk diedit menjadi dianggap “tidak profesional”, dan akhirnya kita berada dalam situasi seperti ini
    • PDF juga mendukung fitur untuk menyertakan informasi struktur dokumen logis. Ini disebut Tagged PDF
      Opsional, tetapi disarankan demi aksesibilitas. Contohnya PDF/UA. Lihat bab 14.7–14.8 di [1]
      [1] https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandard...
    • Di sini, mengatakan “tidak boleh dilakukan” tidak banyak artinya. Di dunia nyata ada sangat banyak situasi yang, bagaimanapun caranya, menuntut penyuntingan PDF
    • Salah satu kesulitannya adalah menandai koreksi yang harus dikembalikan ke dokumen sumber. Kita menerima proof dari penata huruf, lalu harus menandainya agar mereka memperbaikinya
      Teks PDF tidak bisa langsung diubah. Karena penata huruf tidak akan melihat perubahan itu. Alat markup Acrobat memang tidak buruk-buruk amat, tetapi belum setara dengan masa memakai kertas dan pensil merah. Kecuali jika memakai alat “pencil” Acrobat. Saya berharap bagian ini diperbaiki
    • Kalau ini “format deskripsi halaman” dan hanya merepresentasikan tampilan di atas halaman, bukan struktur dokumen, bukankah namanya seharusnya Page Description Format, bukan Portable Document Format?
  • Dua puluh tahun lalu saya bekerja di sebuah surat kabar sebagai penanggung jawab pelat cetak. Kami punya dua “printer” pelat Kodak seharga jutaan dolar, meskipun istilah printer kurang tepat. Kalau ingatan saya benar, emulsi pada pelat terkena sinar ultraviolet lalu larut dalam bak kimia
    Peralatan Kodak itu sering gagal, dan atasan saya biasa membuka langsung file PostScript atau EPS untuk memperbaiki header atau bagian rusak yang dikirim perangkat lunak tata letak. Setelah itu semuanya berjalan lagi. Sebagai catatan, mesin cetak offset web raksasa buatan Jerman kami menjalankan Linux
    Nama atasan saya sepertinya Bill. Dia orang baik yang pernah membawa saya, saat berusia 17 tahun, ke konser Sigur Ros. Jadi sudah ada dua cerita yang tidak ada hubungannya dengan PDF

  • Tulisan yang bagus. Selama kira-kira 5 tahun terakhir membuat DocSpring [1], saya banyak membaca spesifikasi PDF, tetapi rasanya masih baru menggores permukaannya. qpdf adalah alat yang luar biasa, dan alat lain yang saya sukai adalah RUPS [2], yang memungkinkan kita menggali struktur PDF secara mendalam
    [1] https://docspring.com
    [2] https://github.com/itext/i7j-rups