content:
Sebenarnya saat ini saya sedang sibuk dengan banyak hal, tapi karena sedang berduka, saya ingin melakukan sesuatu untuk mengalihkan pikiran. Bapak saya suka membongkar mobil untuk mengalihkan pikiran, sedangkan saya lebih suka memprogram sesuatu yang tidak berhubungan dengan pekerjaan. Hasilnya: hari ini saya mengkompilasi framework Keystone dengan target WebAssembly (Wasm) lalu memberi interface HTML dengan Preact (alternatif React yang ukurannya jauh lebih kecil).
Assembler ini bisa diakses online di https://asm.x32.dev dan sourcenya saya berikan di https://github.com/yohanes/online-assembler . Aplikasinya bisa diakses dengan semua browser modern (Safari, Chrome, Firefix, Edge), termasuk juga mobile browser (sudah ditest di iOS 13 dan Android 10).
WebAssembly (Wasam)
Supaya tidak bingung dengan penjelasan assembler dan webassembly, akan saya jelaskan apa itu WebAssembly (biasa disingkat dengan Wasm). WebAssembly adalah format instruksi biner untuk virtual machine (bisa dibayangkan seperti bytecode Java) . Saat ini target utamanya adalah web browser (saat ini sudah disupport di Firefox, Google Chrome, Safari dan Edge). Di masa depan web assembly ini dihrapkan akan bisa dipakai juga di aplikasi desktop maupun server.
Sekarang ini sudah ada compiler supaya kita bisa mengkompilasi bahasa C, C++, Rust, dsb ke kode WebAssembly. Setelah dikompilasi, kodenya bisa dijalankan di browser. Sayangnya API web browser tidak bisa diakses oleh kode web assembly, jadi diperlukan jembatan berupa kode JavaScript.
Keystone
Keystone merupakan library assembler untuk berbagai arsitektur. Diberikan teks assembly, kita bisa memakai library ini untuk mengubahnya menjadi bahasa mesin. Keystone ini sebenarnya memakai bagian dari libary LLVM, tapi diekstrak bagian assemblernya saja. LLVM sendiri merupakan proyek infrastruktur compiler yang memiliki banyak fitur (parser, optimizer, assembler, linker, debugger, dsb) tapi terlalu kompleks dan terlalu besar jika hanya ingin fitur assemblernya saja.
Untuk keperluan development program dalam assembly, Keystone ini belum terlalu layak pakai karena banyak bugnya dan tidak memiliki fitur macro yang ada di banyak assembler modern. Untuk development, sebaiknya pakai saja assembler dari berbagai compiler yang ada. Keystone ini lebih terpakai untuk riset security, patching program, dan berbagai fungsi kecil lain yang overkill jika memakai assembler lengkap dari sebuah compiler. Contoh pemakaian Keystone adalah untuk menyelesaikan soal CTF semacam yang saya selesaikan dua tahun yang lalu.
Jadi supaya jelas: assembly di WebAssembly tidak berhubungan dengan assembler di library Keystone (saat ini keystone belum mendukung web assembly).
EMSDK
Dengan menggunakan emscripten SDK (emsdk), sekarang kita bisa mengkompilasi banyak library dan program yang ditulis dalam bahasa C/C++ dengan target Web Assembly dengan relatif mudah. Jika program atau library memakai configure, kita bisa menjalankan emconfigure ./configure dan jika memakai cmake, kita bisa menjalankan emcmake cmake. Program emconfigure dan emcmake merupakan wrapper, agar ketika configure/cmake dijalankan, maka compiler dan library yang akan dipakai adalah untuk target WASM.
Tentunya tidak semua program dan library bisa dikompilasi dengan mudah. Contoh kode yang tidak bisa dicompile langsung: kode yang butuh library lain, kode yang butuh akses hardware, kode yang butuh akses layanan sistem operasi tertentu, kode yang memakai kode assembly dalam Intel x86 atau ARM, dan masih banyak lagi kasus khusus lain. Dalam kasus seperti ini, kita perlu melakukan porting manual.
Selain mengkompilasi file C menjadi WASM, emsdk juga menghasilkan file Javascript yang gunanya menjadi jembatan antara Javascript dan WASM. Jembatan ini dua arah: kode C yang memanggil fungsi library standar seperti printf akan memanggil kode JavaScript (misalnya kita arahkan menjadi memanggil console.log), dan kita bisa memanggil kode C dari Javascript.
Optimasi ukuran
Saat ini kode yang dihasilkan dari EMSDK masih belum efisien. Library Keystone ketika dicompile dengan target Web Assembly, hasilnya menjadi file 9.7 megabyte. Saat ini ada proyek lain bernama binaryen yang merupakan infrastruktur compiler untuk WebAssembly. Salah satu toolnya adalah wasm-opt yang dapat digunakan untuk mengoptimasi bytecode WASM. Tool yang lain adalah disassembler Web Assembly (disassembler ini saya pakai untuk menyelesaikan soal CTF).
Setelah dioptimasi, library Keystone yang berukuran 9.7 megabyte berkurang menjadi 5.7 megabyte saja. Ketika didistribusikan, file ini masih akan dikompresi dengan gzip dan hasilnya menjadi 1.5 megabyte. Ukurannya memang tidak kecil, tapi kebanyakan foto dan video ukurannya juga sudah ratusan kilobyte.
User Interface
Bagian berikutnya yang perlu dilakukan adalah membuat user interface yang bagus untuk library yang kita compile tersebut. Untuk program yang memakai Simple DirectMedia Layer (SDL) dan OpenGL, kadang kita bisa langsung menjalankannya karena emsdk sudah menyediakan wrapper untuk API HTML Canvas dan WebGL. Sedangkan untuk aplikasi lain, kita perlu membuat interface HTML dan menggunakan JavaScript untuk memanggil kode C.
Alasan saya memporting Keystone agar bisa memakai assembler keystone terbaru dari browser. Sudah ada yang membuat keystone.js tapi sudah lama tidak diupdate.
Tadinya saya hanya ingin memakai HTML + Javascript murni saja untuk user interfacenya. Tapi setelah saya pertimbangkan lagi, memakai library Javascript akan membuat kodenya jadi lebih terstruktur. Tadinya saya akan memakai React, tapi aplikasi kecil dalam React butuh ratusan kilobyte (terutama karena bagian ReactDOM). Jadi saya memakai Preact yang memakai API yang (hampir) sama dengan React tapi ukurannya hanya 9 kilobyte saja (bahkan hanya 4 kilobyte setelah dikompres).
Development JavaScript Modern biasanya dilakukan dengan menggunakan build system, tapi sebenarnya tidak wajib. Karena program saya ini sangat kecil, saya putuskan untuk tidak memakai build system. Semua kode langsung masuk ke file HTML dan JS. Karena saya memakai WASM, browser harus cukup modern, jadi saya bisa memakai berbagai fitur HTML/JS terbaru tanpa butuh berbagai library polyfill.
Penutup
Salah satu cara belajar teknologi Web Assembly adalah dengan memporting berbagai library dan program ke browser dan membuat atau menyesuaikan user interface agar berjalan di browser. Bahasa C/C++ sudah ada sejak lama, dan sudah banyak hal menarik yang dibuat dalam C, berbagai kode yang sudah ada ini bisa dibawa ke browser dan dieksekusi langsung tanpa butuh server (server hanya sekedar untuk menyimpan file saja, tidak untuk eksekusinya).
Semoga artikel singkat ini berguna untuk memulai eksplorasi Web Assembly, dan semoga assembler onlinenya juga bisa terpakai di masa depan, baik untuk saya sendiri maupun orang lain.
This entry was posted in c, html5, javascript, teknis on May 2, 2020 by admin.
Mengenal Bahasa Pemrograman Lua
Leave a reply
Di kesempatan kali ini saya akan memperkenalkan bahasa Lua. Bahasa ini sebenarnya sudah ada cukup lama (sejak 1993), tapi kurang terkenal secara umum. Lua lebih sering dijadikan bahasa scripting untuk aplikasi dan sering kali nama Lua tidak disebut sama sekali. Lua artinya “Bulan” (moon) dalam bahasa portugis. Lua diciptakan oleh Roberto Ierusalimschy, Luiz Henrique de Figueiredo, dan Waldemar Celes, anggota dari Computer Graphics Technology Group (Tecgraf) di Pontifical Catholic University of Rio de Janeiro, di Brazil.
Lua bisa dipakai untuk membuat program/aplikasi seperti bahasa lain, tapi kelebihan bahasa ini adalah dari awal dirancang untuk diembed dalam sebuah aplikasi lain (terutama dalam bahasa sejenis C). Di-embed ini artinya bisa bisa dipakai untuk sistem plugin atau bisa dipakai untuk mengontrol bagian business/game/app logic sementara bagian yang butuh performance tinggi memakai C atau bahasa lain. Lua juga bisa jadi file konfigurasi yang sangat fleksibel.
Lua dipakai di banyak software misalnya Adobe Lightroom, Nmap, Wireshark, dan lighttpd. Seperti saya sebutkan di awal, sering kali berbagai aplikasi menyebutkan bahasa Lua ini hanya sekilas, dan fitur aplikasinya yang lebih ditekankan dengan nama lain, misalnya dokumentasi Nmap menyebutkan tentang Nmap Scripting Engine (NSE) tapi Lua hanya disebut sekilas di tengah. Lua juga banyak dipakai di berbagai game (misalnya World Of Warcraft, Angry Birds) dan game engine. Interpreter Lua ukurannya sangat kecil sehingga bisa dipakai untuk embedded system/IOT (misalnya NodeMCU dan eLua).
Bahasa Lua
Bahasa Lua menurut saya relatif sederhana, tapi juga sangat fleksibel. Sintaksnya tidak aneh, sedikit mirip BASIC atau pascal. Contohnya seperti ini:
print "hello, berapa umur kamu?"
umur = io.read("*n")
if umur >= 17 then
   print("Halo kakak")
else
   print("Halo adik")
end
Bagi sebagian orang mungkin ini agak aneh mengingat bahasa sekarang sudah tidak lagi memakai kata-kata (“then”, “end”) tapi lebih memakai simbol ({} di C/C++/Java/.NET, indentasi di Python), tapi untuk yang dulu memakai Pascal dan BASIC ini terasa cukup wajar. Sebagian besar syntax Lua mirip dengan bahasa lain, tapi ada beberapa hal yang agak aneh. Di Lua, operator kurang dari, lebih besar, sama dengan, semuanya sama dengan bahasa lain (<, >, =) tapi untuk tidak sama dengan, syntax yang dipakai adalah ~=. Syntax untuk komentar juga agak kurang standar, memakai “–” untuk satu baris, dan memakai –[[ untuk komentar multi baris –]].
Secara umum bahasa Lua cukup mudah dibaca bahkan oleh pemula, tidak seperti bahasa Forth (yang saya bahas sebelumnya) atau bahasa fungsional seperti Scala.
Tipe primitif yang didukung Lua adalah: string, number, dan integer. Struktur data utama di Lua adalah table. Secara umum: tabel memetakan sesuatu ke sesuatu yang lain (seperti Map/Dictionary di bahasa lain). Hampir semua hal di Lua diimplementasikan dengan table. Sebuah array di Lua juga adalah tabel yang memetakan indeks dengan sebuah nilai, dengan nilai index awal default adalah 1. Masalah index ini agak mengganggu bagi saya, karena di bahasa lain biasanya array berbasis 0. Sebuah tabel bisa berisi tabel lain untuk merepresentasikan array multi dimensi.
Sebuah struktur (struct) juga bisa direpresentasikan dalam bentuk tabel (memetakan nama field sebagai string ke nilainya). Di Lua, sebuah fungsi juga bisa masuk ke dalam tabel. Contohnya kita bisa saja membuat tabel yang berisi berbagai operasi matriks yang berisi pemetaan nama operasi, misalnya “multiply” dengan implementasi fungsi perkalian matriks.
Lua juga memiliki konsep metatable, yang bisa digunakan untuk mendefinisikan operasi terhadap sebuah variabel. Dengan setmetatable(variabel, sebuahtabel), kita bisa mendefinisikan berbagai operator dan fungsi yang berlaku untuk variabel tersebut. Jadi jika kita ingin membuat sebuah variabel menjadi sebuah tipe matriks, kita bisa membuatnya dengan setmetatable(variabel1, tabel_operasi_matriks).
Lua tidak memiliki konsep OOP tapi dengan menggunakan berbagai trik table, metatable dan fleksibilitas function di Lua, kita bisa mengimplementasikan Object Oriented Programming. Saya sendiri kurang menyukai ini, kalau saya ingin memprogram dengan paradigma OO, saya akan memilih bahasa lain.
Fitur Lua lain yang menarik adalah coroutine, generalisasi dari subrutin, tapi fitur ini jarang saya pakai. Sebenarnya fitur ini powerful, tapi ketika melakukan embeding Lua ke bahasa lain (terutama C), fitur ini cukup merepotkan karena tidak mudah dipetakan ke C.
Embeding Lua ke bahasa C
Seperti sudah saya sebutkan di atas, fitur Lua adalah sangat cocok untuk diembed ke sebuah aplikasi. Sebenarnya bahasa lain seperti Python dan Ruby juga bisa diembed ke bahasa lain (misalnya C), tapi ada banyak kelebihan Lua:
Ukurannya sangat kecil, ratusan kilobyte. Python butuh minimal beberapa megabyte (disk space dan memori)
Mendukung multi thread (satu thread menjalankan instance Lua terpisah). Untuk embedding multi thread di Python sangat sulit, dan Python memiliki Global Interpreter Lock
Interfacing sangat mudah, baik coding manual atau dengan bantuan SWIG
Implementasi utama Lua adalah dalam bahasa C, walau ada juga Lua untuk Java. Kebanyakan bahasa memiliki build system yang kompleks dan butuh banyak library tambahan. Dalam kasus Lua: kita cuma perlu copy paste semua file .c (kecuali lua.c) ke project kita dan itu sudah cukup. Sebagai catatan: selain implementasi utama Lua, ada juga LuaJIT yang sangat cepat namun memiliki banyak batasan terutama di sistem 64 bit.
Setelah memasukkan semua file C dalam project kita, di bagian program yang butuh Lua, kita perlu menginclude beberapa file:

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

Lalu kita bisa menginstansiasi interpreter Lua. Jika diperlukan, kita bisa membuat banyak instance (misalnya satu di setiap thread). Setelah itu biasanya kita ingin agar library standar Lua diaktifkan, jadi kita memakai luaL_openlibs.
lua_State *L = luaL_newstate();
luaL_openlibs(L);
Biasanya skrip Lua akan diletakkan di luar program, supaya bisa diubah dengan mudah tanpa rekompilasi. Untuk meload dari file, kita bisa memakai luaL_loadfile atau luaL_loadstring jika ingin memakai string. Di banyak Game, file lua dienkrip di file (agar tidak mudah dimodifikasi), lalu didekrip dimemor, dan diload menggunakan luaL_loadstring.

int err = luaL_loadfile(L, "myscript.lua");
if (err) {
       fprintf(stderr, "Failed loading file: %s\n", lua_tostring(L, -1));
       exit(1);
}
Dalam passing parameter ke Lua dan dari Lua, kita menggunakan konsep stack. Kita bisa memasukkan nilai ke stack dengan lua_pushstring/lua_pushnumber/lua_pushinteger, dan bisa mengambil nilai di stack dengan lua_tointeger, lua_tostring, lua_tonumber dan beberapa fungsi lain. Jadi ketika memanggil fungsi di Lua: kita melakukan push value ke stack, dan untuk mengambil nilai dari lua kita akses hasilnya di stack juga.
Kita bisa mencari fungsi yang diimplementasikan di Lua dengan lua_getglobal(L, "namafungsi"), ini akan mempush reference fungsi ke stack. Setelah itu kita bisa mempush nilai parameter untuk fungsi, memanggil fungsinya, dan mendapatkan hasilnya di stack.

lua_getglobal(L, "myfunction");
lua_pushinteger(L, 1); //param 1
lua_pushinteger(L, 2);  //param 2
int err = lua_pcall(L,
    2 /*number of arguments*/,
    1 /*number of result*/,
    0 /*indeks ke error handler, jika 0 maka error akan dipush ke stack*/);
Membuat fungsi di C yang bisa dipanggil oleh Lua juga sangat mudah. Misalnya kita ingin membuat fungsi max yang menerima 2 double dari Lua dan mengembalikan angka terbesar, maka kita cukup membuat ini:

int max_for_lua(lua_State *L)
{
  double num1 = lua_tointeger(L, 1); //param 1 dari Lua
  double num2 = lua_tointeger(L, 2); //param 2 dari Lua

  double max = num1>num2?num1:num2; //logika utama

  lua_pushnumber(L, max); //push ke stack Lua
  return 1; //hanya ada satu nilai kembalian
}
Tentunya keberadaan fungsi ini perlu diberitahukan ke Lua agar bisa diakses oleh skrip Lua. Nama fungsi di C dan Lua bisa berbeda, contohnya fungsi max_for_lua di atas bisa didaftarkan menjadi “my_max” seperti ini:

lua_pushcfunction(lua_state, max_for_lua);
lua_setglobal(lua_state, "my_max");
Penutup
Sering kali saya menemukan di mana saya butuh eksperimen cepat dan tidak ingin sering mengcompile ulang kode program saya. Contoh penggunaan yang baru-baru ini saya lakukan adalah ketika eksplorasi fitur tertentu di iOS. Jika saya mengandalkan objective C atau Swift saja, tiap kali saya mengubah kode (biasanya hanya logic tertentu), akan butuh beberapa detik sampai beberapa puluh detik sampai bisa menjalankan ulang aplikasinya. Walau hanya menekan tombol “run” di XCode yang terjadi di latar belakang adalah: kodenya harus dicompile, dilink, ditandangani secara digital, dicopy ke device, lalu dijalankan. Dengan memindahkan logic ke Lua, saya hanya perlu me-mount direktori dokumen aplikasi dengan ifuse, mengedit file Lua, lalu merestart aplikasinya.
Menambahkan sebuah scripting ke language ke aplikasi memang butuh waktu tapi di sisi lain juga sangat fleksibel karena skrip bisa dimodifikasi dengan cepat dan tidak seperti kode C, tidak perlu dikompilasi ulang. Jika Anda sudah beberapa kali menambahkan fitur scripting ke sebuah aplikasi, menambahkan ke aplikasi berikutnya tidak butuh waktu lama. Untuk aplikasi kompleks kita bisa memakai Simplified Wrapper and Interface Generator (SWIG) untuk mempercepat membuat interface dari C/C++ ke Lua.
Semoga tulisan singkat ini cukup untuk memperkenalkan bahasa Lua dan mungkin juga membuat Anda tertarik untuk menambahkan Lua ke aplikasi yang Anda buat.
This entry was posted in bahasa, lua, teknis on August 3, 2019 by admin.
Dari keyboard ditekan sampai muncul karakter di layar (bagian 3)
Leave a reply
Di bagian sebelumnya sudah dibahas mengenai bagaimana layout text harus dilakukan. Setelah semuanya selesai, maka teks bisa ditampilkan ke layar. Di level aplikasi biasanya kita hanya perlu memanggil semua fungsi dasar untuk menampilkan teks. Di sisi library dan sistem operasi, masih ada langkah ekstra yang harus dilakukan. Teks perlu digambar ke sebuah buffer dan buffer perlu ditampilkan di sebuah permukaan gambar. Driver grafik akan menampilkan buffer tersebut ke layar.
Untuk aplikasi desktop, proses menampilkan teks ini di sisi programmer semudah memanggil fungsi print (mode teks) atau mengeset property tertenty. Jika kita memprogram microcontroller atau embedded system, akan lebih terasa proses berat yang harus dilakukan ketika menampilkan sesuatu. Contoh paling sederhana adalah 7 segment display.
Programmer perlu menyala matikan tiap garis dalam 7 segment display untuk menampilkan angka tertentu.
Display saat ini biasanya menggunakan akses per piksel. Mungkin yang paling sederhana adalah 8×8 dot matrix. Di sini kita perlu mengontrol tiap titik untuk menampilkan huruf/angka/bentuk yang kita mau.
Semakin canggih hardware, biasanya pekerjaan programmer high level akan semakin mudah. Contohnya adalah display LCD jenis seperti ini:
Jpeg
Demikian seri singkat kali ini. Saya akan berusaha membuat seri baru yang membahas dari segi yang lebih low level lagi.
This entry was posted in hardware, teknis, umum on April 11, 2019 by admin.
Dari keyboard ditekan sampai muncul karakter di layar (bagian 2)
Leave a reply
Meneruskan dari tulisan sebelumnya, sekarang kita ke bagian aplikasi. Pertama aplikasi perlu menerima “event” dari Desktop/Window environment. Event ini bermacam-macam, misalnya permintaan untuk meminimize Window, event gerakan mouse, dan event tombol keyboard ditekan.
Setelah tombol ditekan, maka aplikasi akan melakukan update pada struktur datanya. Sebagai pengingat, contoh aplikasi yang saya berikan ada Word Processor. Ini bergantung dari mode saat ini (apakah mode insert atau overwrite, apakah dokumen sifatnya read only dsb). Struktur data yang digunakan pun bisa sangat beragam, tergantung dari fitur yang dimiliki aplikasi.
Dalam sebuah word processor, berbagai algoritma perlu dijalankan sebelum tampilan diupdate di layar. Beberapa algoritmanya misalnya: hyphenation (pemotongan kata), pemeriksa ejaan (dalam kasus tertentu biasanya nanti kata tersebut perlu digaris bawahi merah), perhitungan jumlah kata.
Ketika data di memori perlu ditampilkan di layar, maka ada banyak langkah lagi yang harus dilakukan. Mulai dari pencarian font, layout setiap karakter, dsb.
Sebuah font perlu diload sebelum bisa ditampilkan di layar. Font jaman dulu merupakan font bitmap biasa, tapi font sekarang biasanya merupakan true type font yang memiliki banyak informasi untuk tiap glyph dalam font tersebut. Jika kita memiliki satu kata yang ingin ditampilkan, maka ada kemungkinan:
Satu huruf dipetakan ke satu glyph
Satu huruf dipetakan ke lebih dari satu glyph, contohnya jika ada diacritic
Dua huruf atau lebih dipetakan menjadi satu glyph (contohnya jika ada ligature)
Jika dokumen terdiri dari lebih dari satu bahasa maka hal ini menjadi lebih kompleks lagi, ada bahasa yang ditulis dari kiri ke kanan dan dari kanan ke kiri. Berbagai hal ini biasanya dilakukan dalam tahap yang dinamakan “text-shaping”. Setelah semuanya siap, maka teks bisa ditampilkan di layar.
Bagian berikutnya akan membahas bagaimana teks ditampilkan di layar.
This entry was posted in teknis, umum on December 30, 2018 by admin.
Dari keyboard ditekan sampai muncul karakter di layar (bagian 1)
Leave a reply
Seri tulisan ini akan mencoba menjelaskan apa yang terjadi dari sejak kita menekan tombol di keyboard sampai muncul huruf di layar. Untuk mempersingkat, saya akan mengambil beberapa asumsi:
Keyboard ditekan di sebuah aplikasi yang terbuka (jadi sudah selesai booting)
Sistem operasi yang dipakai modern (bukan DOS, tapi Windows/Linux/OS X)
Aplikasi yang akan saya contohkan adalah sebuah word processor (supaya sederhana, rencananya saya akan menulis dari mengetik di address bar sampai muncul web page)
Keyboard
Ketika tombol di tekan di keyboard, sebuah saklar akan aktif. Ada banyak jenis saklar ini (bisa dibaca di wikipedia) tapi intinya sebuah sirkuit akan tertutup ketika tombol ditekan. Karena jumlah tombol ada banyak, maka digunakan sirkuit matriks pada keyboard untuk mengurangi jumlah koneksi.
Keyboard tidak tahu apa yang tertulis di atas sebuah tombol. Tombol pertama di keyboard QWERTY adalah huruf ‘Q’, tapi di keyboard AZERTY menjadi ‘A’. Keyboard hanya akan mengirimkan kode sebuah tombol, nanti urusan setting di sistem operasi yang akan menginterpretasikan tombol itu menjadi suatu huruf tertentu.
Sebuah keyboard memiliki prosessor, sebuah chip khusus atau microcontroller yang akan melakukan scanning pada matrix keyboard. Di keyboard lama (PS/2), jika ada tombol ditekan maka akan mengirimkan sebuah interrupt ke PC. Di keyboard USB, PC akan melakukan polling (biasanya 150Hz), artinya dalam 1 detik komputer akan bertanya 150 kali pada keyboard: apakah ada tombol yang sedang ditekan?
Jika ingin mengenal bagian ini lebih dalam, kita bisa membeli Arduino, dan keypad matrix sederhana seperti dalam gambar berikut ini.
Atau seperti ini yang lebih jelas terlihat koneksinya
Kita juga bisa membeli keycap satuan untuk keyboard mekanis, dan bahkan merangkai sendiri circuit boardnya. Microcontroller yang digunakan dalam proyek DIY seperti ini biasanya Atmega32u yang mudah diprogram.
Jika ingin membuat keyboard custom sendiri juga tidak sulit. Misalnya kita bisa membuat keyboard yang mengetik alamat email jika satu tombol ditekan. Atau mungkin kita tidak ingin memakai tombol tapi pedal.
Sistem Operasi
Input dari keyboard akan diterima oleh sistem operasi. Untuk keyboard USB, driver HID (human interface device) akan menerima data dari keyboard. Di titik ini, setiap sistem operasi memiliki jalurnya sendiri dalam menangani keyboard.
Di Linux/Unix, jika kita memakai XWindow, maka X Server akan membaca input dari /dev/input/* dan meneruskan eventnya ke berbagai Window yang muncul. Di Windows driver akan mengirimkan message ke System Message Queue.
Shell/Desktop
Ketika sebuah tombol ditekan, maka ada Desktop manager yang akan mengatur: saat ini aplikasi yang aktif yang mana? mana yang menerima input keyboard? kadang ada lebih dari satu aplikasi yang menerima input keyboard, ada aplikasi yang mendaftarkan diri sebagai shortcut handler (misalnya ketika tombol print screen ditekan, maka isi layar akan disimpan ke DropBox).
Berikutnya …
Di sebuah aplikasi akan ada event handler yang menangani input dari keyboard. Ini akan saya bahas di bagian berikutnya.
This entry was posted in teknis, umum on November 30, 2018 by admin.
Code Obfuscation
Leave a reply
Code Obfuscation adalah salah satu bentuk proteksi agar kode sulit dibongkar orang lain. Inti dari obfuscation adalah menyamarkan/membuat kode sulit dibaca. Obfuscation bisa dilakukan manual atau dengan tool yang disebut “obfuscator”. Sementara itu dari sisi reverse engineering, proses mengembalikan dari bentuk samar ini disebut “deobfuscation”.
Arti kata “samar” di KBBI
Meskipun kata “samar” sepertinya cukup berpadanan dengan “obfuscated” saya akan tetap menggunakan istilah inggrisnya di posting ini.
Di posting ini saya hanya ingin memberikan beberapa ilustrasi nyata seperti apa obfuscation ini. Untuk para programmer, ini bisa membantu memproteksi program, dan untuk para reverse engineer bisa berusaha memahami bagaimana obfuscation dilakukan.
Contoh obfuscated code
Obfuscation
Jika kita punya dua fungsi sederhana seperti ini:

int search(int element, int *data, int count)
{
    for (int i =0; i &amp;amp;lt; count; i++) {
          if (data[i] == count)
                return i;
    }
    return -1;
}

int replace_first(int element, int replacement, int *data, int count)
{
    int pos = search(element, data, count);
    if (pos !=-1) {
        data[pos] = replacement;
        return 1;
    }
    return 0;
}

Bentuk obfuscation pertama adalah dengan mengganti nama menjadi nama lain. Ini bisa jadi nama yang sangat singkat misalnya “a”. Pada kode yang dikompilasi menjadi bahasa mesin, nama ini bahkan tidak ada lagi karena tidak diperlukan. Pada bahasa lain yang tidak dicompile jadi bahasa mesin (seperti Java dan Python), nama ini akan tetap ada.
Tanpa membaca kodenya, sudah sulit menebak apa fungsinya ini

int a(int a1, int *a2, int a3);
int b(int a1, int a2, int *a2, int a3)

Bahasa tertentu (seperti Java/C++) mendukung overloading. Beberapa fungsi bisa memiliki nama sama asalkan parameternya berbeda:

int a(int a1, int *a2, int a3);
int a(int a1, int a2, int *a2, int a3)

Cara lain adalah dengan mengubah namanya menjadi menyesatkan, misalnya kedua nama seperti di atas diubah menjadi seperti ini (perhatikan bahwa sengaja count-nya dipindah ke depan untuk menyesatkan pembacanya).

int clear(int count, int *data, int position);
int remove_range(int start, int end, int *data, int element);

Selain penggunaan nama yang menyesatkan, cara lain adalah dengan mengubah control flow program. Contoh sederhananya seperti ini, kita memanggil beberapa fungsi berurutan:

verify_license();
initialize_printer();
initialize_camera();
connect_to_database();

Jika sebuah bahasa mendukung goto maka bentuk obfuscationnya bisa seperti ini:

verify_license();
goto label2;

label1:
initialize_camera();
connect_to_database();
goto label4;

label2:
initialize_printer();
goto label1;

label4:

Jika suatu bahasa tidak mendukung goto urutan operasi bisa disamarkan dengan loop dan switch:
int order[] = {3,1,2,0};
for (int i =0; i &amp;amp;lt; 4; i++) {
   switch (order[i]) {
        case 0: connect_to_database(); break;
        case 1: initialize_printer(); break;
        case 2: initialize_camera(); break;
        case 3: verify_license(); break;
   }
}
Obfuscation kecil seperti contoh di atas masih mudah dimengerti untuk kode yang pendek. Untuk kode yang besar, jumlah “case”-nya bisa puluhan, dan masing-masing nama fungsinya tidak jelas.
Beberapa obfuscation bisa mudah dilihat jika data atau string terlihat jelas, misalnya jika ada kode seperti ini, meskipun kita tidak tahu apa itu kelas x, tapi terlihat bahwa fungsi saat ini berhubungan dengan enkripsi AES:
            throw new x("AES decrypt error");
Jadi bentuk obfuscation berikutnya adalah: string encryption supaya tidak mudah mencari string di dalam program dan mempersulit pemahaman. Tentunya string ini harus bisa didekrip ketika program berjalan, hanya mempersulit pemahaman program.
            throw new x(decrypt(ConstString.ERR1));
Teknik-teknik lain juga bisa ada banyak, saya tidak akan memberikan contoh kode satu persatu. Beberapa yang bisa dilakukan misalnya
Obfuscation di level bahasa mesin/bytecode
Menggunakan exception untuk control flow obfuscation
Menyisipkan kode sampah, misalnya mengurutkan elemen, lalu mencari elemen tengah, menjumlahkan semua elemen, lalu hasilnya tidak dipakai
Menggunakan thread untuk memecah algoritma menjadi beberapa bagian sehingga lebih sulit di mengerti
Mengubah logika program, misalnya menambahkan angka 2312312 di awal, lalu di akhir dikurangi lagi 2312312
Menggunakan enkripsi dan/atau kompresi untuk sebagian kode program yang diload secara dinamis
Memakai custom virtual machine
Perlu diperhatikan bahwa obfuscation tertentu bisa membuat program jadi lebih lambat. Sekedar mengganti nama method tidak akan membuat lebih lambat (bahkan biasanya malah membuat sedikit lebih cepat), tapi mengganti control flow biasanya membuat kode menjadi lebih lambat. Obfuscation juga membuat debugging menjadi lebih sulit (karena memang itu tujuannya). Jadi sebaiknya obfuscation hanya dilakukan di akhir development.
Saya tidak bisa menyarankan tool obfuscator tertentu karena memang jarang melakukan obfuscation pada kode saya, silakan search “obfuscator” dan nama bahasa yang Anda pakai di search engine. Tool obfuscator yang banyak saya temui adalah Proguard (gratis) yang dipakai untuk kode Java/Android.
Di dunia Javascript ada istilah minifier, yaitu tool untuk membuat kode Javascript mejadi lebih kecil. Ini dilakukan dengan mengganti nama variabel, menghapus spasi, komentar dsb. Secara umum ini juga berfungsi sebagai obfuscator sederhana.
Deobfuscation
Secara umum tidak ada cara generik yang membuat obfuscated code bisa dibaca dengan mudah. Tapi ada beberapa tool yang bisa membantu proses deobfuscation spesifik untuk bahasa/teknologi tertentu.
Contohnya jika bertemu dengan kode JavaScript yang sudah minified, maka kita bisa memakai JavaScript beautifier. Ini tidak bisa mengembalikan nama variabel, hanya membuat teks yang sulit dibaca menjadi lebih mudah dibaca (tool beautifier ini sekarang sudah built in di Developer Tools-nya Google Chrome).
Contoh lain: ada yang membuat tool untuk mendekrip String untuk APK yang ditulis dalam Java. Tapi tool ini tidak selalu jalan untuk semua protektor. Setiap kali ada yang membuat tool untuk otomasi sesuatu, pembuat obfuscator menambahkan satu hal kecil sehingga toolnya harus diupdate (atau bahkan ditulis ulang).
Cara yang pasti berhasil adalah kombinasi manual dengan debugger dan sedikit programming. Hal utama adalah memahami obfuscation apa yang dilakukan: apakah stringnya dienkripsi, apakah nama methodnya diubah, apakah control flow-nya berubah, dsb.
Jika sekedar nama methodnya diubah, maka kita harus membaca kodenya dan melakukan renaming untuk mendapatkan nama yang benar. Ini bisa dilakukan berdasarkan beberapa hal, misalnya:
string yang muncul (misalnya “AES Error” mengindikasikan AES)
konstanta yang dipakai (misalnya 0x9E3779B9 mengindikasikan penggunaan enkripsi XTEA)
fungsi yang memanggil. Misalnya jika suatu fungsi dipanggil dari fungsi AES, maka kemungkinan itu hanyalah subrutin AES
fungsi yang dipanggil, misalnya jika aplikasi C memanggil “system” maka kemungkinan ini fungsi menjalankan command line lain
algoritma yang dipakai. Beberapa algoritma sederhana (search, sort, traversal) mudah diidentifikasi
Untuk mendapatkan gambaran sebuah program seperti menyusun sebuah puzzle. Kita bisa mulai dari bagian-bagian yang jelas. Untuk puzzle bagian yang jelas adalah pinggiran puzzle, dan bagian-bagian yang unik. Untuk program kita bisa mulai dari titik awal program (main di sistem POSIX, Activity di Android, dsb), dan titik di mana program memanggil fungsi eksternal.
Jika string dienkripsi, kita bisa membuat breakpoint di method dekrip-nya agar bisa mendapatkan hasil string-nya. Jika control flow-nya obfuscated, kita bisa membuat beberapa breakpoint untuk berhenti di tiap titik, jadi kita bisa mengetahui urutan yang sebenarnya. Selain menggunakan breakpoint dan debugger, kita juga bisa menggunakan Frida atau tool sejenis.
Penutup
Walaupun obfuscator bisa membantu melindungi program, tapi faktor keamanan lain harus tetap diperhatikan. Attacker yang gigih akan bisa membuka segala jenis obfuscation, hanya akan memperlama saja. Di kasus tertentu kombinasi obfuscator dan pentester yang kurang berpengalaman justru bisa membuat aplikasi kurang aman karena testing aplikasi kurang optimal.
Contohnya begini: aplikasi memakai enkripsi, lalu kodenya diobfuscate. Aplikasi ini ditest oleh pentester yang tidak bisa melakukan reverse engineering terhadap kode tersebut, dan pentester menganggap aplikasi tersebut aman karena dia tidak dapat melakukan tampering terhadap nilai yang dikirimkan. Ketika aplikasi dirilis dan dibongkar oleh seorang reverse engineer yang berpengalaman, dia dapat mengubah nilai yang dikirimkan dan ternyata tidak dicek di sisi server (aplikasinya jebol).
Jadi sebaiknya: pentester diberi akses pada kode yang belum obfuscated dan kode final yang sudah. Ini akan lebih optimal karena kerja pentester lebih cepat, tidak perlu membongkar obfuscation dan lebih aman (seluruh fungsi bisa ditest dengan baik). Ini dengan asumsi bahwa pentester memiliki keahlian untuk membaca kode dengan baik.
Semoga artikel singkat ini bisa memberikan gambaran mengenai apa itu code obfuscation dan berbagai batasannya.
This entry was posted in security, teknis, umum on July 23, 2018 by admin.
Matematika dan Programming
2 Replies
Di kala senggang saya masih menjawab pertanyaan via Facebook/Email/Telegram dan banyak calon programmer yang sudah takut sebelum belajar programming: apakah akan butuh matematika? Jawabannya singkatnya tergantung. Tergantung ingin memprogram apa dan sedalam apa.
Matematika dasar tentunya sangat diperlukan, misalnya perkalian, pembagian, penjumlahan pengurangan. Hampir di semua bidang diperlukan ilmu dasar geometri. Misalnya tentang sistem koordinat ketika menggambar grafik (atau sekedar mengatur posisi teks di sebuah halaman web).
Pengetahuan dasar ini penting, dan ini berarti anak yang masih sangat kecil dan belum memiliki dasar matematika harus berhenti dulu belajar di titik tertentu. Ini pengalaman saya dalam mengajari anak saya ketika dulu mengajari dia programming di usia 4 tahun (sekarang sudah 7 tahun). Logika boolean juga perlu dipahami, sekedar AND, OR, dan NOT sudah cukup untuk sebagian besar kasus.
Untuk pemrograman grafik, terutama grafik 3D diperlukan pemahaman matriks dan vektor. Segala operasi matrix akan terlihat secara visual ketika memprogram grafik. Matrik dan vektor juga dipakai di Machine Learning. Jika fokusnya ingin mengolah data besar, maka berbagai ilmu matematika seperti: statistika, linear programming, graph, dan banyak konsep yang rumit akan terpakai.
Kadang hampir semua topik matematika terpakai dalam satu aplikasi. Contohnya untuk membuat game yang kompleks, diperlukan berbagai matematika untuk grafik (matriks, vektor), dibutuhkan AI untuk menggerakkan musuh (yang butuh matriks, vektor, statistika, dsb), dan untuk mencari jalan terpendek atau terbaik kadang dibutuhkan teori graph, dan masih banyak lagi komponen sebuah game.
Saya masih bisa memberikan banyak contoh lain aplikasi matematika dalam programming, tapi hal yang paling penting adalah: matematika (selain topik yang paling dasar) bisa dipelajari selagi kita belajar memprogram.
Sebelum masuk ITB, saya dulu belajar programming otodidak mulai dari SMP. Ketika saya belajar pemrograman sambil belajar matematika SMP/SMU, saya merasa lebih bisa mengerti karena bisa dicoba dalam bentuk program. Contohnya konsep fungsi dan komposisi fungsi. Saya bisa membuat sebuah fungsi di dalam bentuk kode program yang memanggil fungsi lain, dan saya bisa bereksperimen dengan itu. Jadi konsep “fungsi” tidak lagi menjadi hal yang abstrak.
Simbol summation (∑) di kode program hanyalah sebuah loop penjumlahan. Demikian juga dengan ∏ yang hanya loop dengan isi perkalian.
Demikian juga dengan topik matriks dan vektor waktu SMU. Saya mendapatkan banyak ilmu justru dari buku cara membuat game 3D yang saya baca dan saya coba waktu itu. Topik di kelas terasa sangat abstrak, tapi di kode program, bisa terlihat apa gunanya memiliki matriks dan berbagai sifat matriks lainnya.
Kalau Anda tertarik lebih dalam lagi mengenai berbagai topik matematika yang nantinya akan terpakai, silakan baca posting panjang ini (Math for Programmers) yang sudah ditulis seseorang di tahun 2006. Artikel tersebut juga membahas secara detail bagaimana belajar matematika yang lebih baik.
Jadi kesimpulannya adalah: belajar programming bisa dimulai asalkan sudah memiliki pengetahuan matematika yang dasar. Belajar konsep lanjut bisa dilakukan sambil belajar programming, dan bagi sebagian orang belajar dengan cara ini lebih mudah. Tapi jika Anda sudah punya dasar matematika yang bagus tentunya programming akan lebih mudah lagi dan Anda bisa membuat program yang lebih baik lagi. Contohnya: jika Anda punya dasar matematika yang bagus untuk AI, maka Anda bisa membuat game dengan AI yang lebih baik dari yang tanpa AI.
This entry was posted in teknis, umum on May 15, 2018 by admin.
Modifikasi Aplikasi Android
5 Replies
Ada banyak alasan kenapa kadang kita ingin memodifikasi aplikasi Android, dan ada banyak cara untuk melakukannya. Beberapa alasan saya pernah memodifikasi Android di antaranya: untuk pentest, untuk membuat aplikasi bisa berjalan lagi, dan untuk mencurangi game.
Untuk pentesting, modifikasi yang sering perlu dilakukan adalah: mematikan certificate pinning, mematikan root checking, dan juga menambahkan tracing untuk melihat logika aplikasi lebih jelas. Jam tangan murah dari China yang saya pakai memakai aplikasi Android untuk notifikasinya. Suatu saat aplikasi ini tidak bisa dipakai karena servernya di China sudah dimatikan, dengan mengubah aplikasinya, jam ini jadi tetap terpakai. Untuk masalah mencurangi game, sudah pernah saya tuliskan di blog saya yang lain.
Sekarang saya ingin menjelaskan beberapa cara untuk mengubah aplikasi Android. Saya tidak akan membahas aplikasi spesifik, karena tiap aplikasi berbeda, dan bahkan satu aplikasi yang sama bisa berubah total di rilis berikutnya. Asumsinya adalah aplikasi memakai kode Java/Smali (kebanyakan aplikasi seperti ini) dan bukan HTML/JS atau teknologi lain. Teknologi HTML/JS lebih mudah dimodifikasi, tapi beberapa yang lain seperti Unity (.NET), dan Rhomobile (Ruby) membutuhkan penanganan khusus .
Cara pertama adalah yang paling dasar, dan paling sering saya pakai: patching smali. Caranya adalah: APK diekstrak dengan apktool menjadi smali, di-edit, dicompile lagi, lalu disign. Kelebihan cara ini: hampir selalu berhasil, tidak perlu rooting HP dan menginstall software. Kekurangannya: tidak user friendly, harus mengedit kode smali yang cukup rawan salah. Dengan pendekatan ini, aplikasi asli perlu diuninstall, dan aplikasi baru menggantikan aplikasi lama.
Dengan unpack/repack APK, kita juga bisa menambah atau mengubah library native, termasuk juga menambahkan LD_PRELOAD seperti yang pernah saya bahas sebelumnya.
Pendekatan variasi lain dari cara tersebut adalah dengan DexPatcher. Ini sama saja dengan mengedit smali (aplikasi asli diuninstall lalu diinstall yang baru) tapi kita menuliskan kode patching dalam Java sehingga tidak rawan salah. Tentunya selain cara di atas ada cara variasi lain. Contohnya untuk aplikasi tertentu hasil dekompilasi menjadi Java cukup baik sehingga mudah dikompilasi ulang.
Kelemahan kedua cara tersebut adalah: data lama aplikasi akan dihapus (kita perlu login ulang). Kelemahan lain adalah: signature aplikasi berubah. Beberapa aplikasi memiliki proteksi sehingga tidak akan mau berjalan jika signature aplikasi berubah, jadi bagian checking ini perlu dipatch juga. Kelebihan utama kedua cara di atas adalah: tidak butuh root, dan APK yang sudah diubah mudah disebarkan ke orang lain.
Pendekatan lain adalah dengan XPosed framework, yang sudah pernah saya bahas sebelumnya. Dengan pendekatan ini: signature aplikasi tidak berubah, kita membuat perubahan di luar aplikasi menggunakan bahasa Java. Kelemahan cara ini adalah: handphone harus terinstall XPosed framework. Tiap kali kita memodifikasi modul framework, handphone perlu direstart (bisa soft restart saja agar lebih cepat) untuk mengaktifkan modifikasinya.
Pendekatan sejenis XPosed yang lebih dinamik adalah Frida. Dengan Frida kita bisa memanipulasi berbagai hal secara dinamis menggunakan JavaScript, termasuk juga mengganti beberapa kode native. Jika ingin mudah, frida bisa dijalankan pada HP yang sudah diroot, dengan ini signature APK tidak berubah. Tapi jika tidak memungkinkan, kita bisa memodifikasi APK agar meload library Frida (modifikasi APK akan mengubah signature aplikasi).
Kelemahan Frida dibandingkan XPosed adalah: perubahan yang dilakukannya tidak permanen. Tapi kelemahan ini juga menjadi suatu kelebihan: modifikasi mudah dilakukan dan tidak perlu restart HP setiap kali
Contoh skrip Frida untuk salah satu soal Flare On
Selain XPosed dan Frida, sebenarnya ada juga Cycript dan MobileSusbtrate tapi keduanya sudah lama tidak diupdate dan tidak mendukung Android terbaru.
Semua cara di atas sebaiknya dikuasai, karena penerapannya tergantung kebutuhan. Contohnya: jika modifikasi hanya temporer (untuk pentest atau menyelesaikan CTF) mungkin Frida akan lebih baik. Jika ingin menyebarkan modifikasi tanpa menyertakan aplikasi asli (karena masalah hak cipta) maka XPosed bisa digunakan. Xposed juga cocok jika ingin membuat perubahan semi permanen.
Ketika ada sistem operasi baru, biasanya XPosed dan Frida tidak langsung bisa dipakai jika ada perubahan mendasar di sistem operasi, jadi tetap perlu tahu cara modifikasi manual.
This entry was posted in android, teknis on March 24, 2018 by admin.
Memahami Static dan Shared Library di Linux
2 Replies
Saya masih sering melihat programmer C dan juga administrator yang bingung dengan konsep shared library. Shared library adalah file berisi kode yang bisa diload saat program dieksekusi (runtime). Karena diload pada runtime, maka sebuah shared library bisa digunakan oleh lebih dari satu program.
Penjelasan mengenai static dan shared library biasanya membingungkan, jadi di posting ini saya akan menjelaskan dengan banyak contoh. Sebenarnya hampir semua contoh di tulisan ini berlaku juga untuk lingkungan POSIX lain selain Linux, tapi saya hanya mencoba kode ini di Linux 64 bit dengan compiler gcc. Di balik layar, program gcc sebenarnya akan memanggil berbagai program lain (preprocessor, assembler, linker) tergantung pada parameter yang kita berikan tapi agar penjelasannya sederhana, saya akan memakai gcc saja dan tidak akan menjelaskan apa yang terjadi di balik layar.
Kode monolitik
Kita mulai dari kode yang sangat sederhana seperti ini:
/*file: main.c */
#include <stdio.h>

double operation(double a, double b)
{
        printf("Plus operation\n");
        return a+b;
}

int main(int argc, char *argv[])
{
        double a = 5;
        double b = 3;
        printf("Result of operation (%.2f, %.2f) is: %.2f\n", a, b, operation(a, b));
        return 0;
}
Karena semua sudah ada di satu file, maka ini bisa dikompilasi dan jalankan langsung.
gcc main.c -o main
Memecah source code
Di sini ada satu fungsi bernama operation yang hanya melakukan operasi sangat sederhana. Anggap saja fungsi ini rumit dan penting dan ingin kita pisahan agar bisa dipakai oleh orang lain. Sekarang operation saya pindahkan ke operation.c
/*file: operation.c */
#include <stdio.h>

double operation(double a, double b)
{
        printf("Plus operation\n");
        return a+b;
}

Dan kode main menjadi:
/*file: main1.c */
#include <stdio.h>

int main(int argc, char *argv[])
{
        int a = 5;
        int b = 3;
        printf("Result of operation (%d, %d) is: %d\n", a, b, operation(a, b));
        return 0;
}

Jika kita coba compile main.c saja, seperti ini:
gcc main.c -o main
maka akan ada warning DAN error. Isi errornya adalah:
/tmp/cc08zl1h.o: In function `main':
main2.c:(.text+0x45): undefined reference to `operation'
collect2: error: ld returned 1 exit status
Ini karena compiler tidak bisa menemukan implementasi dari fungsi operation. Kita perlu memberikan file operation.c
gcc main1.c operation.c -o main
Sekarang kompilasi berhasil, tapi tetap ada peringatan:
implicit declaration of function ‘operation’
Compiler C tidak tahu menahu mengenai fungsi bernama operation. Secara default (karena alasan sejarah), compiler akan menganggap fungsi tersebut mengembalikan sebuah int
Jika kita coba jalankan:
Plus operation
Result of operation (5.00, 3.00) is: 0.00
Hasilnya 0.00 karena fungsi operation dianggap mengembalikan int. Ini bisa diperbaiki dengan menambahkan deklarasi fungsi sebelum main:
/*file: main2.c */
#include <stdio.h>

/* INI YANG DITAMBAHKAN */
double operation(double a, double b);

int main(int argc, char *argv[])
{
        int a = 5;
        int b = 3;
        printf("Result of operation (%d, %d) is: %d\n", a, b, operation(a, b));
        return 0;
}
Sekarang kita coba lain:
$ gcc main2.c operation.c -o main
Dan berhasil:
Plus operation
Result of operation (5.00, 3.00) is: 8.00
Object code
Tapi sekarang kita tidak ingin orang mengetahui source code operation.c, kita bisa menjadikan operation.c menjadi object code:
$ gcc -c operation.c
Hasilnya adalah file operation.o. Ini bisa dikirimkan ke orang lain yang memiliki main.c dan kompilasi bisa dilakukan dengan (perhatikan: operation.c diganti menjadi .o)
$ gcc main2.c operation.o -o main
Tapi ada satu masalah di sini: penerima operation.o tidak tahu fungsi apa di dalam operation.o dan apa parameternya. Sebenarnya nama fungsinya saja bisa dilihat dengan nm atau objdump tapi apa parameternya tidak bisa. Contoh dengan nm:
$ nm operation.o
                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 T operation
                 U puts
File Header
Untuk memudahkan, kita perlu membuat file header: operation.h, isinya bisa seperti ini saja:
double operation(double a, double b);
Dan di file yang memakai fungsi tadi, bisa menggunakan include:
/*file: main3.c */
#include <stdio.h>
/* INI YANG DITAMBAHKAN */
#include "operation.h"

/*ini tidak lagi diperlukan, karena sudah diinclude dari operation.h*/
/*double operation(double a, double b);*/

int main(int argc, char *argv[])
{
        int a = 5;
        int b = 3;
        printf("Result of operation (%d, %d) is: %d\n", a, b, operation(a, b));
        return 0;
}
Sekarang kita sudah bisa mengirimkan file operation.h dan operation.o untuk dipakai oleh seseorang. Orang tersebut tidak tahu implementasinya (kecuali dengan dekompilasi), dan bisa memakai fungsinya dengan mudah. Perlu dicatat bahwa ada beberapa standar file object, secara umum: file dari compiler yang sama akan kompatibel, tapi tidak dijamin kompatibel dengan kode dari compiler yang berbeda.
Biasanya file header tidak hanya berisi deklarasi fungsi, tapi juga deklarasi struktur, misalnya seperti ini:
struct point {
int x, y;
};

void init_point(struct point *p);
Jika file ini di-include sekali saja, maka tidak ada masalah. Tapi jika tidak sengaja diinclude dua kali, maka akan ada error:
 error: redefinition of ‘struct point’
Bagaimana mungkin menginclude “tidak sengaja” dua kali (atau lebih?). Contohnya ada file circle.h menginclude file point.h, dan file square.h juga menginclude point.h. Jika program utama menginclude circle.h dan square.h maka point.h akan diinclude dua kali. Masalah ini sering muncul sehingga ada konvensi membuat header seperti ini:
#ifndef POINT_H
#define POINT_H
struct point {
int x, y;
};

void init_point(struct point *p);
#endif
Ketika file diinclude kali pertama, semuanya akan normal dan POINT_H akan terdefinisi. Jika diinclude lagi, maka tidak akan terjadi apa-apa karen POINT_H sudah terdefinisi.
Sekarang ada masalah baru. Andaikan kita ubah operation.c sehingga menggunakan int, tapi lupa mengubah header operation.h
/*file: operation.c */
#include <stdio.h>

int operation(int a, int b)
{
        printf("Plus operation\n");
        return a+b;
}

Maka semuanya akan berhasil dicompile seperti semula, tapi hasilnya tidak seperti yang diharapkan. Untuk mengatasi ini, kita sebaiknya menginclude header di implementasi, seperti ini:
/*file: operation.c */
#include <stdio.h>
/* BARIS INI DITAMBAHKAN */
#include "operation.h"

int operation(int a, int b)
{
        printf("Plus operation\n");
        return a+b;
}

Sekarang jika deklarasi dan implementasi tidak konsisten akan mucul error:
operation.c:5:5: error: conflicting types for ‘operation’
 int operation(int a, int b)
     ^~~~~~~~~
In file included from operation.c:3:0:
operation.h:4:8: note: previous declaration of ‘operation’ was here
 double operation(double a, double b);
Static Library
Sekarang header kita sudah bagus. Tapi ada masalah lain: jika hanya ada satu file saja, maka satu file objek sudah cukup. Tapi jika ada banyak file objek, ini akan merepotkan. Contohnya saja, jika kita memiliki kode untuk menangani bentuk, dan menggunakan banyak objek seperti: circle.o, square.o, polygon.o, dsb, maka kompilasinya akan cukup repot (perintahnya menjadi panjang). Berbagai file objek bisa disusun jadi satu library statik untuk memudahkan kompilasi.
Kita bisa menyusun satu file saja:
ar rcs libop.a operation.o
Atau banyak file
ar rcs libop.a operation.o operation2.o
Progam “ar” akan menciptakan arsip library, dengan flag “c” untuk membuat library (create) jika belum ada, “r” untuk menggantikan (replace) file operation.o jika sudah ada di arsip dan “s” untuk membuat indeks. Kita bisa melihat isi arsip .a dengan parameter “t” (test):
ar t libop.a
Sudah menjadi konvensi untuk menamai suatau library statik dengan prefiks lib dan dengan suffiks a. Kita bisa memakai library ini ketika mengkompilasi dengan menggunakan opsi l diikuti nama library tanpa prefix lib (cukup:op saja)di gcc:
gcc main3.c -lop
Tapi ini akan error:
/usr/bin/ld: cannot find -lop
collect2: error: ld returned 1 exit status
Karena defaultnya gcc hanya mencari di path library. Path standar ini bisa dilihat dengan:
$ gcc -v -Wl,verbose 2>&1|grep LIBRARY
Di komputer saya outputnya seperti ini:
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/7/:/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/7/../../../:/lib/:/usr/lib/
Intinya: kita bisa memindahkan file libop.a ke salah satu direktori tersebut, atau cukup beritahu path tempat library kita berada. Karena berada di direktori saat ini, kita bisa memakai titik tunggal (.):
gcc main3.c -L. -lop -o main
Sekarang program berhasil dilink dengan library, dan berjalan seperti biasa. Sebagai catatan, sebenarnya gcc juga mengijinkan kita langsung menyebut nama file librarynya, walau biasanya ini jarang dilakukan
gcc main3.c libop.a -o main
Andaikan kita salah melink ke library yang tidak mengandung implementasi fungsi operation, maka akan muncul error:
main.c:(.text+0x40): undefined reference to `operation'
collect2: error: ld returned 1 exit status
Ketika kita menggunakan static library, maka kode dari library tersebut di “copy paste” ke file executable. Untuk menjalankan program kita, kita tidak butuh lagi libop.a karena kodenya sudah ada di executable. Jika ada program lain yang memakai library yang sama, program itu mengandung kode yang sama (duplikat).
Andaikan kita mengupdate operation.c dengan versi yang lebih baik (misalnya ada perbaikan bug, atau ada optimasi baru) maka kita harus mengcompile ulang program kita agar mendapatkan perbaikan tersebut.
Shared Library
Dalam kasus tertentu kita ingin agar hanya ada satu kode saja yang dipakai bersama. Misalnya sebuah XML parser dipakai oleh banyak program, jika ada update pada parser XML kita tidak ingin mengkompilasi ulang seluruh program yang memakai library tersebut. Dalam kasus ini kita sebaiknya menggunakan shared library. Satu library yang bisa dipakai banyak program.
Untuk mengcompile operation.c menjadi shared library bisa dilakukan dengan:
gcc -fPIC -shared operation.c -o libop.so
Cara kompilasi juga sama dengan static library (jika ada libop.a dan libop.so, maka yang .so diprioritaskan):
gcc main3.c -L. -lop -o main
atau:
gcc main3.c libop.so -o main
Tapi jika kita coba jalankan:
$ main
./main: error while loading shared libraries: libop.so: cannot open shared object file: No such file or directory
Kode dari libop.so tidak disalin ke executable dan masih ada di libop.so, jika kita ingin menjalankan kita harus melakukan salah satu dari ini: menyalin libop.so ke path library sistem, menambahkan path system baru (bisa mengedit /etc/ld.so.conf) atau memberikan pathnya dengan LD_LIBRARY_PATH.
Untuk melihat pencarian yang dilakukan oleh sistem:
$ ldconfig -v
Jika kita mengubah file /etc/ld.so.conf, kita perlu menjalankan ldconfig sebagai root untuk mengupdate cache.
Cara termudah tanpa akses root adalah menambahkan ke environment LD_LIBRARY_PATH (titik adalah direktori saat ini, bisa saja diganti path lain, misalnya /home/yohanes/mylibs).
$ export LD_LIBRARY_PATH=.
$ ./main
Plus operation
Result of operation (5.00, 3.00) is: 8.00
Cara di atas akan membuat semua perintah berikutnya menggunakan path library yang baru. Jika kita hanya sekedar ingin mengubah path untuk satu perintah saja, maka cara ini lebih baik:
$ LD_LIBRARY_PATH=. ./main
Plus operation
Result of operation (5.00, 3.00) is: 8.00
Fleksibilitas shared library
Sekarang kita lihat fleksibilitas shared library dengan membuat shared library baru dengan nama sama. Saya membuat file baru: operation-mult.c yang mengalikan operand.
#include <stdio.h>

double operation(double a, double b)
{
	printf("Multiply operation\n");
	return a*b;
}
Agar lebih jelas, saya masukkan file ini dalam direktori “op-mult”. Lalu saya compile seperti ini:
gcc -fPIC -shared op-mult/operation-mult.c -o op-mult/libop.so
Sekarang jika saya jalankan program sebelumnya, tapi dengan path libop.so yang berbeda:
$ LD_LIBRARY_PATH=./op-mult ./main
Multiply operation
Result of operation (5.00, 3.00) is: 15.00
Output program berubah: dari penjumlahan menjadi perkalian. Jika kita memiliki lebih dari satu library dengan nama yang sama di path yang berbeda, maka library yang ditemukan pertama akan diload
$ LD_LIBRARY_PATH=./op-mult:. ./main
Multiply operation
Result of operation (5.00, 3.00) is: 15.00
[/code]
Bagaimana jika kita punya file yang kebetulan namanya sama, tapi tidak memiliki fungsi yang kita butuhkan? Hasilnya akan error:
./main: symbol lookup error: ./main: undefined symbol: operation
Override Fungsi dengan LD_PRELOAD
Ada trik menarik yang bisa dilakukan dengan menggunakan shared library, yaitu mengganti implementasi fungsi lain dengan fungsi milik kita sendiri. Trik ini bisa dipakai untuk runtime patching.
Dengan menggunakan program ltrace kita bisa melihat fungsi library apa yang dipanggil oleh sebuah program. Untuk mudahnya, kita akan memakai program paling pertama, yang tidak memakai library, versi monolitik:
ltrace ./main
puts("Plus operation"Plus operation
)                                                = 15
printf("Result of operation (%d, %d) is:"..., 5, 3, 8Result of operation (5, 3) is: 8
)                = 33
+++ exited (status 0) +++
Ada 2 call yang dibuat oleh program tersebut: puts dan printf. Sebenarnya di dalam program kita memakai printf saja, tapi compiler mengoptimasi printf tanpa parameter tambahan menjadi puts saja. Jika kita meminta compiler untuk tidak menghapus file assembly dengan opsi -S
$ gcc -S main.c -o main
Maka kita bisa melihat bahwa dalam operation memang digunakan puts sedangkan dalam main digunakan printf:
Cara lain melihat ini adalah dengan objdump -d nama_executable untuk melihat kodenya.
Untuk mudahnya sekarang kita ingin mengganti puts agar melakukan hal lain: mencetak string “EXTRA” sebelum mencetak string yang seharusnya.
/*file: myputs.c*/

#define _GNU_SOURCE
#include <dlfcn.h>

int (*orig_puts)(const char *s);

int puts(const char *s)
{
        if (orig_puts == 0) {
                orig_puts = dlsym(RTLD_NEXT, "puts");
        }
        orig_puts("EXTRA: ");
        return orig_puts(s);
}

Lalu compile filenya sebagai shared library, tapi sertakan juga libdl (untuk fungsi dlsym).
$ LD_PRELOAD=./libmyputs.so ./main-standalone
EXTRA:
Plus operation
Result of operation (5, 3) is: 8
Dalam kode pengganti milik kita, pertama yang dilakukan adalah mencari alamat fungsi “puts” yang asli, lalu meletakkannya di variabel bernama orig_puts (tiipenya adalah sebuah function pointer). Setelah itu kita bisa memanggil fungsi aslinya. Tentunya kita tidak harus memanggil fungsi aslinya jika memang ingin mengganti seluruhnya.
Beberapa kegunaan LD_PRELOAD ini misalnya: untuk membetulkan bug tanpa mengubah program. Kadang ini juga bisa digunakan untuk testing, jika sebuah program memakai random, lalu crash hanya jika nilai tertentu dihasilkan oleh random, maka kita bisa menggunakan LD_PRELOAD untuk mengganti fungsi random agar nilai kembaliannya sebuah nilai yang tetap.
LD_PRELOAD Ini juga bisa digunakan untuk cracking program, misalnya jika program hanya bisa berjalan hanya sebelum expiration date, maka kita bisa membuat fungsi time() yang selalu mengembalikan tanggal tertentu.
Penutup
Pemahaman mengenai library bisa membantu menyelesaikan banyak masalah dan tidak perlu coba-coba yang memakan banyak waktu. Semoga posting ini cukup menjelaskan seluk beluk library di Linux.
This entry was posted in linux, teknis on February 14, 2018 by admin.
XPosed: Framework sakti untuk modifikasi Android
2 Replies
Topik kali ini agak advanced, tapi juga pratis. XPosed adalah sebuah framework open source yang memungkinkan kita membuat modul untuk memodifikasi sistem dan aplikasi Android yang ditulis menggunakan Java. Dari sudut pandang programming, framework ini menarik karena memungkinkan kita menambahkan dan mengintersepsi kode pada aplikasi closed source Android, sedikit mirip Aspect Oriented Programming.
XPosed bekerja dengan memodifikasi runtime Android (Dalvik/Art) sehingga menjadi mungkin untuk memanggil kode custom di awal atau akhir sebuah method apapun. Perhatikan bahwa yang dimodifikasi adalah runtime Android saja, jadi hanya kode yang ditulis dalam Java dan diinterpretasikan oleh Dalvik atau Art runtime saja yang bisa diintersepsi, kode native tidak bisa. Ada framework lain, misalnya Cydia yang bisa mengintersepsi kode native juga, tapi Cydia versi Android ini agak lambat perkembangannya (saat ini belum mendukung Android 5 dan 6).
Untuk memakai XPosed, yang harus Anda lakukan adalah: menginstall recovery alternatif (CWM, TWRP, dsb) dan menginstall frameworknya (tergantung ponsel Anda, ini mungkin bisa membatalkan garansi). Anda juga perlu menginstall XPosed installer yang akan memanage modul mana saja yang aktif.
Mari kita mulai dengan contoh yang praktis tentang intersepsi kode. Jika kita punya kode seperti ini:
Kita bisa mengintersepsi ini dengan mengembalikan agar isValidLicense selalu menjadi true. Kita juga bisa memodifikasi agar validateLicense segera kembali (tidak melakukan apapun, jadi tidak akan melempar exception). Dalam kasus yang sebenarnya, kita harus teliti, misalnya mungkin di dalam ada validateLicense kode lain untuk mensetup versi premium jika license valid (jadi tidak bisa kita patch agar selalu kembali).
Dalam contoh di atas method checkRoot melakukan pemeriksaan apakah device di-root oleh pengguna, dan cara memeriksanya adalah dengan menggunakan XML yang berisi daftar command dan package yang harus diperiksa. Dalam kasus seperti ini (ini penyederhanaan dari kasus nyata yang saya temui), maka kita bisa juga mengganti parameter input XML menjadi XML kosong.
Berikut ini contoh kode untuk mem-patch agar isValidLicense selalu mengembalikan true.
Beberapa baris pertama hanya mengimpor package yang kita butuhkan. Berikutnya kita perlu mengimplementasikan IXposedHookLoadPackage. Di dalam handleLoadPackage, kita bisa memfilter untuk package aplikasi mana saja hooking ini akan kita lakukan. Dalam kasus ini saya hanya tertarik pada satu aplikasi saja. Dalam kasus tertentu kita ingin menghook semua aplikasi, misalnya kita bisa membuat modul untuk melakukan SSL Unpinning untuk semua aplikasi.
Berikutnya yang harus kita ketahui adalah signature dari method yang akan kita hook. Untuk aplikasi yang sourcenya terbuka, atau untuk aplikasi yang mudah didekompilasi karena tidak diobfuscate, hal ini mudah dicari. Jika aplikasi di-obfuscate, hal ini agak lebih sulit. Dalam contoh ini package yang dimaksud adalah es.yohan.example dan methodnya adalah isValidLicense yang memiliki parameter berupa String.
Ada dua hook yang tersedia: beforeHookedMethod dan afterHookedMethod. Dalam beforeHookedMethod, kita bisa mengubah parameter yang masuk ke program (atau bisa juga sekedar melakukan logging atau mengirimkannya ke tempat lain), dan dalam afterHookedMethod kita bisa menerima dan atau mengubah nilai kembalian method. Dalam contoh di atas, saya hanya mengeset agar hasilnya selalu true.
Mungkin sekarang Anda bisa melihat kelemahan XPosed: modifikasi hanya bisa dilakukan di awal dan di akhir method. Jika Anda ingin memodifikasi sesuatu di tengah-tengah, misalnya mengubah konstanta yang tertanam di logika program (misalnya if (x>2127)), atau sekedar mengubah “kurang dari” menjadi “lebih dari” maka sulit melakukannya dengan XPosed.
Jika masih ingin mengubah detail sebuah method dengan XPosed, caranya adalah dengan menulis ulang method itu, dan di beforeHookedMethod kita memberitahu XPosed framework agar tidak memanggil method aslinya. Dalam kasus tertentu lebih mudah mengedit file APK-nya.
Secara praktis apa saja yang bisa dilakukan dengan kemampuan XPosed ini? Sudah banyak orang menuliskan modul untuk Xposed, dari mulai sekedar mengubah kosmetik Android (mengubah tampilan ini dan itu), menambahkan fitur tertentu (misalnya menambahkan Zoom ke aplikasi Instagram), memblokir iklan di berbagai aplikasi (termasuk juga Youtube yang sekarang memasukkan iklan bukan hanya di awal video tapi juga di tengah video jika videonya panjang), memperbaiki offset GPS di China, dan masih banyak lagi.
Ada juga modul untuk meningkatkan privasi (misalnya XPrivacy dan PMP), dengan memblok berbagai request dari aplikasi Android yang nakal atau mengembalikan data palsu. Contoh: banyak sekali aplikasi yang meminta akses ke contact list, ternyata mengupload seluruh phonebook kita ke server mereka (dengan berbagai alasan, misalnya untuk fitur referal, dsb).
Penghematan batere juga bisa dilakukan, misalnya dengan memblok aplikasi agar tidak bisa auto start, membatasi akses sensor, dsb.
Kebanyakan modul di repository XPosed berguna untuk mengatasi masalah sangat spesifik yang dimiliki oleh pengguna (misalnya ada yang nggak suka jika app yang baru diinstall langsung memiliki shortcut di home screen, ada yang nggak suka jika VPN meminta konfirmasi, dsb). Menurut saya itu kelebihan utama XPosed: kita bisa memodifikasi Android dengan mudah sesuai kemauan kita. Sebagai programmer, modifikasi ini bisa dilakukan meskipun kita tidak memiliki source code aplikasinya.
Secara praktis bagai saya pribadi: Sebagai pentester, saya kadang menemui aplikasi yang melakukan pengecekan root dengan cara yang unik dan modul XPosed seperti RootCloak tidak cukup. Saya kadang melakukan patching aplikasi langsung (jika masih testing tahap development), dan mengembangkan frameworknya (jika aplikasi sudah di appstore, karena biasanya sudah stabil)
Kadang saya juga perlu mengintersepsi komunikasi dengan enkripsi yang custom (misalnya memakai AES dua kali), dalam kasus ini intercept via proxy tidak cukup (datanya sudah dienkrip, dan tidak bisa dengan mudah didekripsi karena formatnya custom). Di dalam kodenya pasti ada sesuatu yang mengenkrip data sebelum dikirim dan mendekrip data yang diterima, dengan mengintercept titik tersebut, saya tidak perlu menulis program khusus untuk dekrip/enkrip ketika testing.
Saya juga pernah membuat modul khusus untuk intersepsi Blackberry Messenger (BBM). Cara kerja modulnya seperti ini: saya membuat web server di Android yang bisa menerima pesan untuk dikirimkan, dan pesan itu saya inject langsung ke proses BBM. BBM selalu menyimpan message dalam format internalnya setelah diterima, jadi kita bisa mengakses message dari conversation manapun. Perlu dicatat bahwa modul ini bisa saya kembangkan dengan mudah karena di versi awal mereka tidak melakukan obfuscation, dan ketika sudah diobfuscate, saya masih bisa melihat mapping class/methodnya berdasarkan berbagai pesan error yang ada di method tersebut.
Untuk membuat XPosed module sendiri, sudah ada berbagai tutorial di Internet, tapi saya akan memberikan panduan singkat, sekaligus sebagai catatan untuk diri sendiri.
Pertama: buat proyek baru dengan Android studio. Pastikan instant run dimatikan karena tidak kompatibel dengan Xposed. Tidak perlu template khusus untuk membuat modul XPosed.
Kedua: edit file gradle dengan menambahkan dependensi: provided 'de.robv.android.xposed:api:82'. Tentunya versi 82 bisa diganti dengan versi terbaru.
Ketiga: implementasikan IXposedHookLoadPackage, ini sudah dicontohkan di atas.
Keempat: buat file app/src/main/assets/xposed_init yang adalah file teks dan isinya adalah nama package + kelas yang mengimplementasikan IXposedHookLoadPackage tersebut. Ini akan dipakai oleh Xposed untuk mendari kelas mana yang akan diload saat booting.
Terakhir: edit file manifest agar dikenali sebagai modul XPosed. Pertama tambahkan atribut xmlns:tools="http://schemas.android.com/tools" di tag manifest (ini sekedar untuk menghilangkan warning). Lalu tambahkan beberapa metadata berikut di dalam tag application:
<meta-data  android:name="xposedmodule"
android:value="true" />

<meta-data  android:name="xposedminversion"
android:value="54" />

<meta-data  android:name="xposeddescription"
android:value="Joe Hack Module"
tools:ignore="ManifestResource" />
Tentu saja bagian tersulit adalah mencari tahu bagian mana yang perlu dihook untuk mengimplementasikan fungsionalitas tertentu. Tapi menurut saya ini juga sekaligus menjadi bagian yang paling menarik: kita jadi lebih mengerti internal sistem Android.
Modifikasi dengan XPosed framework melengkapi hack Android yang lain. Rooting aplikasi tidak cukup untuk mengubah internal program (contohnya untuk pentest aplikasi custom). Modifikasi dan compile ROM sendiri bisa mengubah hal-hal yang di luar kemampuan XPosed, tapi tetap tidak bisa mengubah aplikasi. Modifikasi aplikasi dengan cara patching manual bisa dilakukan, tapi cara ini lebih repot, dan akan sulit jika kita ingin mempatch banyak aplikasi sekaligus.
Sebagai pembuat aplikasi, mengobfuscate aplikasi Anda adalah salah satu cara untuk mempersulit hooking dengan XPosed framework. Contohnya: aplikasi Youtube sering diobfuscate dan sering diupdate sehingga modul seperti YoutubeAdaway tidak jalan.

label: ceb


content:
Penyesuaian atau perubahan adalah cara tubuh merespons nilai yang diperolehnya dari lingkungan. Organisme mutan hidup dan tidak boleh dihancurkan atau direduksi. Manusia dan hewan tidak hanya terkompresi di lingkungan. Tumbuhan, seperti organisme, juga harus beradaptasi dengan lingkungannya. Ada tumbuhan yang hidup di air, rawa, garam dan lahan kering. Oleh karena itu, metode pemindahan sifat tanaman bervariasi tergantung pada iklimnya.
Untuk melakukan hal tersebut, selain nutrisi, pertumbuhan, respirasi, pertumbuhan limbah dan pertumbuhan patogen, salah satu ciri organisme lain adalah kemampuan beradaptasi atau beradaptasi dengan lingkungan.
Perubahan ini mempengaruhi manusia, hewan dan tumbuhan bahkan dalam kondisi lingkungan yang paling kritis.
Cara Tumbuhan Menyesuaikan Diri
Artikel bersumber dari portaldemisterios.com
Bagaimana tumbuhan beradaptasi dengan lingkungannya jika manusia dan hewan dapat beradaptasi secara alami?
Perubahan atau perubahan juga dikenal sebagai keinginan makhluk hidup untuk hidup di lingkungannya sendiri. Jika tubuh beradaptasi dengan lingkungannya, ia akan bertahan hidup.
Pada saat yang sama, itu tidak dapat dihapus. Pesawatnya serupa karena makhluk beradaptasi dengan lingkungannya. Jadi, mari kita cari tahu bagaimana tanaman beradaptasi dengan iklimnya.
Pesawat adalah keanekaragaman hayati yang merupakan bagian dari kerajaan tumbuhan. Kerajaan itu meliputi tumbuhan luar ruangan, bibit, hutan cemara, tumbuhan berbunga dan peserta latihan fisik. Selain itu, tumbuhan hijau biasanya mengandung selulosa pada dinding selnya.
Tidak seperti hewan dan manusia, tumbuhan beradaptasi dengan lingkungannya. Anda bahkan dapat menyingkirkan situasi yang paling sulit sekalipun. Jenis-jenis penyesuaian tanaman diberikan di bawah ini.
Tanaman yang bertahan hidup ditanam. Penyesuaian merupakan ciri tumbuhan atau tumbuhan yang hidup di suatu daerah atau wilayah tertentu. Tumbuhan dapat dibedakan menjadi tiga jenis tergantung pada habitatnya.
Tumbuhan air
Tanaman di atas permukaan air tubuh. Akarnya ada di air. Memiliki lubang udara di bagasi atau bagasi. Daunnya tumbuh di atas air. Contoh tumbuhan hidrofit adalah primitif, eksim dan eceng gondok.
Hibrida
Tanaman yang hidup di daerah dengan kelembaban tinggi. Tubuhnya terdiri atas akar, batang dan daun. Gerak biasanya tidak terlihat karena tanah. Daun kecil biasanya melengkung atau melengkung. Contoh tanaman hibrida adalah pakis, pakis, lumut, lumut, daun merah muda dan willow.
Xerofit
Tumbuhan yang hidup di lahan gersang. Tanaman ini memiliki daun yang rimbun dan ramping, yang terkadang berubah meski tanpa duri, sisik dan daun. Ini memiliki pegangan tebal dan jaring drainase. Akar panjang. Contoh tumbuhan xerophytic adalah kaktus, kaktus, bunga liar, pohon palem, setai dan lain-lain.
Sesuatu tentang bibit tanaman
Perubahan antimikroba dibedakan menjadi tiga jenis: xerofit, hidrofit, dan hidrofit. Jenis penyesuaian ini disebut transisi. Baca terus untuk memahami pertanyaan rilis dengan mudah.
Cara Mengendalikan Tanaman Xerophytic
Tumbuhan Xerophytic merupakan salah satu jenis tumbuhan yang mampu bertahan hidup pada kondisi kering dan lemah seperti gurun pasir. Varietas tanaman xerophytic dibedakan menurut bentuk daun dan bagian lainnya. Contoh dari jenis tanaman tersebut adalah sebagai berikut.
1. Kaktus
Kaktus merupakan tumbuhan gurun yang menyimpan banyak air di dalam batangnya untuk bertahan hidup meski dalam kondisi kering. Selain itu, perlindungan ini diberikan oleh daun dan duri di dekat batang, yang membantu mengurangi penguapan yang berlebihan.
Kaktus menjadi ranting hijau tebal besar yang berfungsi sebagai reservoir. Bagian luar alas kaktus memiliki lilin tahan lembab dan lapisan putih yang sama.
Keunggulan lain yang dimiliki kaktus adalah akarnya yang panjang, sehingga sangat penting untuk mendapatkan air darinya. Saat musim kemarau, tanaman kaktus digunakan untuk menyiram kaki mereka lebih baik dari tanaman lain.
2. Batang pohon
Saat musim panas tiba, Anda akan melihat bahwa teh ini ramah lingkungan dengan meletakkan daun di setiap rantingnya. Sejauh yang kami ketahui hal ini dilakukan untuk mengurangi risiko penguapan tinggi yang berujung pada kekeringan dan kematian.
Pohon teh tidak hanya tidak berbuah, tapi juga pohon lain seperti Kedong Kong dan Mahang.
3. Workshop Dompet
Semer pi merupakan kelompok tumbuhan yang dapat hidup di iklim tropis dan memiliki akses yang mudah terhadap serangga (serangga dan hewan kecil). Untuk mempercepat perburuan, sperma mengeluarkan bau unik yang disukai oleh spesies serangga.
Beberapa bagian kantong benih yang digunakan untuk menggali korban berisi cairan khusus. Oleh karena itu, kami dapat memastikan bahwa vesikula seminalis berubah untuk menerima nutrisi.
4. Putri malu
Promosi diri yang tidak tahu malu untuk Produk Balistik dan tawaran besar untuk pisau kecil yang rapi untuk Anda. Daunnya tiba-tiba menutup ketika terkena rangsangan luar, jadi itu adalah tanaman yang wanita pemalu melindungi dirinya dari rangsangan luar.
Manajemen Tumbuhan
Tumbuhan hidrofobik merupakan nama tumbuhan yang hidup di lingkungan perairan. Jenis hidrofilik ini mengapung di air dan hidup dengan cara menyerap unsur hara (nutrien) langsung ke dalam air. Contoh hidrofit:
1. Lotus
Ekosistem yang diadopsi oleh tumbuhan eksim tidak melepaskan air dari tambak dan tambak. Sebab, daun teratai itu lebar tapi sempit.
Ia beradaptasi dengan lingkungan akuatik dan melarutkan sebagian besar air melalui daun teratai yang lebar.
Selain itu, batang teratai memiliki batang yang kosong, yang penting untuk memudahkan pernapasan bahkan saat batang dan akarnya terendam.
2. Gulma air
Seperti teratai, tumbuhan air hidup di air. Untuk bertahan hidup dalam kondisi lembab, gulma mengandung pembusukan yang mengandung cadangan udara. Kain seperti jamur di pangkal tanaman tidak tenggelam atau berenang.
3. Lahan Basah
Jika Anda sedang berada di pantai, Anda mungkin sudah tidak asing lagi dengan lahan basah. Ya, tanaman ini biasa dijumpai di daerah air asin. Oleh karena itu, rawa dapat direstorasi oleh akarnya dan akarnya dapat menyaring kandungan garamnya.
Jika Anda mengambil terlalu banyak garam, garam akan menembus daun. Rawa-rawa mengandung pneumofor, yang biasanya terjadi bila terjadi kekurangan air.
Cara memperbaiki tanaman hidrofilik
Hgrofit merupakan konsep tumbuhan yang dapat hidup di daerah basah seperti hutan tropis. Contoh depan untuk tanaman hidrofilik.
Dengan menyesuaikan jumlah daun dan tulang, penyerang melindungi dirinya dari lingkungan, membuatnya lebih sempit, lebih lebar, dan lebih besar. Tujuan dari perubahan tersebut adalah untuk meningkatkan produktivitas tanaman ikan.
Bagaimana tumbuhan terbentuk karena perubahan morfologi
Transformasi adalah proses di mana tumbuhan mengubah bentuk tubuh luarnya untuk beradaptasi dengan lingkungan luar. Ada beberapa contoh morfologi tumbuhan:
Tanaman kaktus beradaptasi dengan panas yang ekstrim, mengurangi ukuran daun dan pemangkasan. Udara aromatik melarutkan air dari tubuh, yang mengurangi laju respirasi melalui penguapan dan volume daun.
Ada akar dalam yang menembus ke rawa, yang merupakan contoh mutasi genetik yang menyebabkan gelombang besar di sekitar pantai mencegah peredaran tanaman.
Teratai dan pohon busuk kuno, mereka bisa berenang di air hidup. Jika ada dua tanaman di batang pohon, dia pasti pemberani.

warc-type: conversion

warc-identified-content-language: ind,eng

content-type: text/plain

label: id


content:
Ada banyak jenis reksa dana mengungkap perbedaan trading Forex dan trading spot bitcoin yang bisa Anda coba, tetapi untuk Anda yang terhitung masih baru dalam dunia investasi, cobalah reksa dana pasar uang maupun reksa dana campuran. Tahap ini akan menjanjikan keuntungan yang lebih besar dan tentu saja dibarengi dengan resiko bisnis yang lebih besar pula, karena itu pastikan kita telah dalam keadaan benar-benar siap saat mengambil keputusan untuk melakukan hal ini.
Sedangkan saldo pembayaran yang pasif, dimana debitur dalam negeri menjual semuanya menggunakan mata uang asing, maka akan menurunkan nilai tukar mata uang nasional. Teknik Forex Terbaik 2018, Teknikal Updates Forex USDCAD Sesi Eropa, 27 Juli 2018Primary Sidebar. Teknik Forex Sebenar Videokamera Kursy walutowe Starachowice. Misi para suhu. Binary options broker new traders Binary Binomo membayar Options Signals.
Ada banyak broker yang menawarkan akun demo. Sumber gambar: Percaya hanya dengan broker binary options yang memiliki kantor di Eropa? Dilakukan dengan uang virtual australian systems hair. Misalnya, jika Anda bertrading pada time frame 5 menit, expiry time dapat ditentukan pada waktu 15 menit. Syukur, lepas tu baru depa aktif balik lepas beberapa bulan menunggu. Hak untuk menarik persetujuan. Anda dapat menarik persetujuan Anda untuk memproses informasi pribadi Anda setiap saat. Penarikan tersebut tidak akan mempengaruhi keabsahan pemrosesan berdasarkan persetujuan Anda sebelumnya. Perlu diketahui bahwa jika Anda menarik persetujuan Anda, Anda mungkin tidak dapat memperoleh manfaat dari fitur layanan tertentu yang mana memerlukan pemrosesan informasi pribadi Anda.
Membuat token lebih mudah daripada membuat coin karena Anda tidak harus membuat kode-kode blockchain dari awal atau memodifikasi blockchain yang sudah ada. Anda tinggal menggunakan template dari platform yang ada seperti Ethereum.
2. Aturan Spread-nya rendah, di kisaran satu digit saja, bahkan bisa di bawah 1 Pip. Medan - palembang acangz said. Market on close artinya mengungkap perbedaan trading Forex dan trading spot bitcoin harga sesuai dengan harga penutupan.Other Features.
Praktis dan lebih update. Halo, saya adalah Ibu Jessica Apa strategi perdagangan algoritmik, pemberi pinjaman uang pribadi, apakah Anda berhutang? Pastikan Anda membacanya dengan seksama.
Bagaimana? apakah Anda tertarik memakai robot forex kami sehabis mempelajarinya? Anda dapat langsung download “GRATIS” di sini! Potensi payout yang ditawarkan perlu dipertimbangkan sesuai dengan money management dalam rencana trading Anda. Hal ini penting untuk memastikan bahwa hasil trading Anda masih berada di jalur yang tepat untuk mencapai target jangka panjang.
Mengungkap perbedaan trading Forex dan trading spot bitcoin - Opsi biner pullback strategi
Sebuah sistem yang dibuat dengan segudang fasilitas terbaik membutuhkan biaya yang mengungkap perbedaan trading Forex dan trading spot bitcoin tidak sedikit.
Lorong itu terbagi menjadi dua yaitu lorong bagian atas dan lorong bagian bawah.
Untuk file simulasi proteus dari project ini kamu bisa download gratis pada link yang sudah diberikan dibawah ini, silahkan di modifikasi sesuai kebutuhan. Kedua bisns itu memang bergerak di dunia maya atau di internet dan sam — sama mendapatka banyak keuntungan. Nah apa itu put? Binomo withdrawal. Cara withdraw Binomo dengan mandiri visa - option trading bahasa Indonesia.
Mungkin hanya kalimat ini yang paling meringkas keseluruhan dari bisnis trading forex. Jika anda telah memiliki strategi trading pastinya anda harus/sudah tahu kapan saat yang tepat untuk melakukan transaksi, kapan saat yang tepat untuk tidak transaksi, dan kapan saatnya untuk keluar dari market (close posisi / take profit / stop loss). Jangan pernah melanggar aturan/rule yang sudah anda buat sendiri dalam strateginya, Sabar untuk tidak melakukan apapun sampai saat yang tepat datang.
Dalam kasus ini, penyidik tidak menemukan ceceran darah di lokasi korban pertama kali ditemukan. Darah hanya ada di sekitar tubuh korban. Olymp Trade dan IQ Option adalah beberapa perusahaan broker terbesar yang tersedia untuk investor ritel. Kedua pemain ini berspesialisasi dalam digital options. Kedua platform ini memiliki banyak klien yang puas dan telah beroperasi di pasar selama bertahun-tahun. Popularitas mereka tidak merata di berbagai wilayah di dunia. Olymp Trade lebih populer di Asia Selatan dan memiliki banyak pengguna di Turki. IQ Option mendapatkan banyak penggemar di Amerika Selatan, terutama Brasil. Kedua broker option ini memiliki penawaran yang serupa untuk para trader. Kami akan membahas persamaan dan perbedaannya dalam artikel ini untuk memudahkan Anda memilih broker yang dapat memenuhi harapan Anda. Tentu saja pencapaian nya di lakukan dengan kerja keras mengungkap perbedaan trading Forex dan trading spot bitcoin dan motivasi yang tinggi.

warc-identified-content-language: ind


content:
1. Jangan menyalin review atau mengisi dengan asal. Review yang kamu kirimkan akan melewati sistem moderasi Jobplanet.
Jika review kamu tidak sesuai dengan panduan kami, review kamu akan ditolak dan kamu tidak akan mendapatkan akses ke semua review di Jobplanet.
2. Tulislah secara obyektif. Seburuk-buruknya tempat kerja kamu, pasti ada sisi baiknya. Begitu pun sebaliknya. Sebaik-baiknya perusahaan, pasti ada hal-hal yang masih dapat diperbaiki. Tulislah pro dan kontra secara berimbang.
3. Selalu menulis dengan tujuan membantu orang lain. Dengan menempatkan diri sebagai pembaca, yang kamu tulis pasti akan cenderung memberi informasi atau wawasan yang berguna untuk para pembaca.
Kebijakan pengajuan review
Kami berkomitmen untuk melindungi komunitas kami dari review yang bersifat tidak benar dan dapat mempengaruhi rating dan review kami. Kami menyeleksi setiap review sebelum menampilkannya di situs Jobplanet. Apabila ada laporan terhadap suatu review, kami akan menanggapi masalahnya dan mengambil tindakan yang tepat.
Review ditolak apabila: 1. Informasi tidak relevan dan tidak memberikan wawasan berguna tentang perusahaan 2. Konten memuat pencemaran nama baik atau dugaan tanpa bukti yang ditujukan kepada orang, departemen atau posisi tertentu, dll. 3. Konten memuat pernyataan kasar, istilah-istilah susah dimengerti atau format tidak benar (singkatan atau huruf besar semua) 4. Informasi bersifat rahasia perusahaan 5. Perusahaan tidak ditemukan atau informasi perusahaan yang diberikan tidak akurat
"“Perusahaan ini membimbing karyawannya bagaimana untuk menjadi seorang market researcher dengan lingkungan yang membangun dan saling membantu satu sama lain.” "
Reviewmu memberikan wawasan dan pengetahuan yang berguna untuk calon karyawan lain.
"“Bagus jenjang kariernya bagi pegawai, bergerak di bidang perbankan, menghasilkan tenaga terdidik dan terlatih melalui pendidikan yang diberikan kepada karyawan.” "
Satu menit yang kamu sisihkan dapat membantu calon pekerja lain menemukan karier yang tepat.
"Adanya tunjangan dan sistem kesejahteraan dalam perjanjian belum tentu Anda akan menerimanya. Tapi informasi yang sensitif seperti sulit didapatkan."
Review yang kamu berikan akan membuat calon karyawan dapat mengetahui kondisi dan keadaan tempat kerja sebenarnya.
"Andai info ini sudah ada dari dulu! Saya tidak akan terjebak di perusahaan ini selama enam bulan belakangan... setidaknya ada yang bisa menolong saya."
Reviewmu akan menolong para Fresh Graduates pencari kerja yang masih memerlukan arahan.
Mohon dibaca
Gaji tidak kami terima jika:
1. Jumlah gaji terlalu jauh dari rata-rata untuk posisi dan pekerjaannya
2. Nama perusahaan tidak dapat ditemukan
Bila jenis pekerjaan atau posisi kamu tidak ada dalam daftar yang kami sediakan, mohon untuk memilih yang menurut kamu paling cocok dan mendekati.
Untuk menjaga kredibilitas info gaji, semua informasi yang masuk akan melalui sistem moderasi Jobplanet terlebih dahulu.
Hal-hal yang perlu diingat:
1. Masukkan jumlah gaji dan tunjangan nett yang kamu terima setiap bulan (take-home pay)
2. Masukkan bonus atau insentif yang kamu terima (jika ada) secara terpisah pada kolom yang disediakan
Sedikit tips untuk menulis review
1. Jangan menyalin review atau mengisi dengan asal. Review yang kamu kirimkan akan melewati sistem moderasi Jobplanet. Jika review kamu tidak sesuai dengan panduan kami, review kamu akan ditolak dan kamu tidak akan mendapatkan akses ke semua review di Jobplanet.
2. Berikan tips berguna untuk yang sedang mencari kerja. Ceritakan pengalaman proses rekrutmen di perusahaanmu dan apa saja yang kamu lalui. Berikan tips atau saran bagi yang akan melewatinya juga.
3. Selalu menulis dengan tujuan membantu orang lain. Dengan menempatkan diri sebagai pembaca, yang kamu tulis pasti akan cenderung memberi informasi atau wawasan yang berguna untuk para pembaca.
Kebijakan pengajuan review
Untuk meningkatkan kredibilitas info interview dan mencegah manipulasi terhadap peringkat perusahaan, semua informasi akan melewati sistem moderasi Jobplanet terlebih dahulu.
Review ditolak apabila: 1. Perusahaan tidak ditemukan atau informasi perusahaan yang diberikan tidak akurat 2. Informasi bersifat rahasia perusahaan 3. Konten memuat pernyataan kasar, istilah-istilah susah dimengerti atau format tidak benar (singkatan atau huruf besar semua) 4. Konten memuat pencemaran nama baik atau penghinaan yang ditujukan kepada orang, departemen atau posisi tertentu, dll. 5. Informasi tidak relevan karena tidak memberikan wawasan berguna tentang perusahaan
"Awalnya saya hanya mempersiapkan diri untuk pertanyaan interview yang selama ini sudah sering ditanyakan, ternyata banyak pertanyaan interview yang di luar dugaan. Untungnya saya sudah melihat tips dan bocoran interview dari Jobplanet dan saya lulus! Mimpi saya menjadi kenyataan!"
Karyawan yang berhasil lolos adalah berkat info interview yang kamu tulis.
"Saya telah menyerah dengan perusahaan asing karena interview dalam bahasa Inggris. Namun, bocoran interview di Jobplanet menyebutkan bahwa bagian bahasa Inggris tidak sesulit yang saya bayangkan. Saya bisa interview dengan percaya diri dan sekarang saya bekerja di perusahaan ini."
Mengetahui proses interview yang sesungguhnya, berhasil mendapat pekerjaan baru.
Kebijakan pengajuan review
Untuk meningkatkan kredibilitas info interview dan mencegah manipulasi terhadap peringkat perusahaan, semua informasi akan melewati sistem moderasi Jobplanet terlebih dahulu.
Review ditolak apabila: 1. Perusahaan tidak ditemukan atau informasi perusahaan yang diberikan tidak akurat 2. Informasi bersifat rahasia perusahaan 3. Konten memuat pernyataan kasar, istilah-istilah susah dimengerti atau format tidak benar (singkatan atau huruf besar semua) 4. Konten memuat pencemaran nama baik atau penghinaan yang ditujukan kepada orang, departemen atau posisi tertentu, dll. 5. Informasi tidak relevan karena tidak memberikan wawasan berguna tentang perusahaan
Tutup
{{= caption}}
광고 동영상 영역 입니다.
닫기
x
Selamat Datang Kembali! Temukan perusahaan impian Anda di Jobplanet dan raih karier yang lebih baik!
Login dengan Email E-mail ini tidak valid. Alamat email Kata sandi ini tidak valid. Kata Sandi (8 karakter atau lebih)
Selalu login
Lupa Kata Sandi?
atau login dengan
Belum punya akun? Daftar
이 광고 후원으로 잡플래닛이 운영됩니다
Setelah 10 detik, Anda akan mendapat akses untuk melihat review lainnya
Tidak ingin menunggu? Silakan Login
Login dengan Email E-mail ini tidak valid. Alamat email Kata sandi ini tidak valid. Kata Sandi (8 karakter atau lebih)
Selalu login
Lupa Kata Sandi?
atau login dengan
Belum punya akun? Daftar
Laporkan
Close
Mohon pilih alasan untuk laporan Anda
Mengandung informasi tidak benar Mengacu pada orang tertentu Mengungkap informasi rahasia Lain-lain Min 10 karakter
Batal Laporkan
Laporan telah diterima.
Tutup
Laporan ini juga akan diteruskan ke penulis ketika proses selesai.
OK
Gaji PT Prima Wahana Caraka
Info Gaji Karyawan PT Prima Wahana Caraka di situs Jobplanet terbaru tahun 2017 yang bersumber dari karyawan/mantan karyawannya.

label: ko

label: ms

label: en


content:
Anda sedang mencari Jasa Pendirian CV BATU terbaik dan terpercaya. Dapatkan sekarang dengan KLIK DISINI!!!
Cara buat CV cepat di BATU, Jasa pendirian CV BATU. Memiliki usaha sendiri memang menjadi salah satu hal yang sangat diinginkan oleh banyak orang. Pengaturan waktu yang fleksibel dan juga tidak ada tuntutan dari atasan memang menjadi salah satu alasannya. Tentu saja dengan mendirikan usaha sendiri. Maka sudah dipastikan anda akan bebas membawa kemana bisnis anda tersebut. dalam mendirikan sebuah usaha pasti akan ada beberapa syarat yang harus dipenuhi agar bisnis yang didirikan tersebut bisa berkembang dengan lancar. Sehingga anda juga harus mengetahui syarat utama dari pendirian usaha sebelum anda memulainya. Di Indonesia sendiri memang sudah semakin banyak masyarakat yang mulai menggeluti dunia usaha secara mandiri. Baik itu sebagai usaha sampingan maupun sebagai usaha pokok. Bahkan tidak hanya usaha berskala besar saja, badan usaha dengan skala kecil dan menengah juga ikut meramaikannya akhir-akhir ini. Badan usaha tersebut juga sudah mulai dari bisnis kuliner, pakaian, aksesoris, elektronik dan lain sebagainya. Akan tetapi tidak sedikit pula masyarakat yang lebih memilih mendirikan perusahaan. CY atau persekutuan komanditer memang merupakan suatu perusahaan dengan pemodal minimal 2 orang. Pemodal dalam perusahaan ini memang ada dua tipe yaitu pemodal aktif dan juga pemodal pasif. Peran sekutu aktif adalah bertanggung jawab sepenuhnya terhadap pemberian model dan yang pasti juga kelangsungan dari perusahaan tersebut.
Akan tetapi sebelum itu, apakah anda sudah mengetahui apa itu CV? CV merupakan singkatan dari Commoditaire vennootshcap. Dalam pembuatan sebuah CV, meskipun memiliki skala yang lebih kecil dari PT. Akan tetapi juga melewati beberapa proses atau mekanisme tertentu dalam pembuatannya. bahkan jika dibandingkan dengan PT, Jasa pendirian CV BATU cepat di buat CV cepat di BATU, Buat CV di BATU, ini memang jauh lebih mudah dan sederhana. Sehingga bisa memakan waktu yang tidak lama. CV ini memang bisa berupa persekutuan yang didirikan oleh beberapa pihak atau beberapa orang yang ingin melakukan usaha dalam satu bidang tertentu. Dari beberapa orang atau pihak tersebut pasti ada satu pihak yang bertindak sebagai pemimpin dan pasti juga untuk pihak lainnya yang berfungsi sebagai penyimpan barang serta sebagai pemodal. Siapa sih yang tidak ingin buat CV di BATU dengan cara cepat dan juga tepat. Semua orang pasti juga ingin melakukannya bukan. Akan tetapi, apakah anda sudah mengetahui bahwa untuk bisa membuat CV yang tepat dan cepat. Maka kita juga membutuhkan jasa pendirian CV BATU yang berpengalaman dan juga terpercaya. Jika anda saat ini sedang membutuhkan jasa pendirian CV BATU terbaik dan terpercaya. Maka akan lebih baik jika anda segera memilih jasa pendirian CV BATU di www.popjasa.id saja.
Prosedur Untuk Buat CV Cepat di BATU Terbaik Dan Terpercaya
Cara buat CV di BATU dalam suatu perusahaan memang tidak susah seperti cara membuat perseroan terbatas atau PT. Cara buat CV di BATU untuk sebuah perusahaan sendiri akan lebih mudah jika anda mengikuti prosedur yang berlaku. Hal tersebut disebabkan karena buat CV jogja di BATU ini adalah hal penting. Maka ada baiknya jika anda bekerja sama dengan biro jasa pembuatan CV terbaik dan juga profesional. Maka teliti lah dalam memilih jasa pembuatan CV perusahaan tersebut. Sebab jika ada kesalahan, maka hal tersebut justru akan membahayakan proses pembuatan CV perusahaan anda. cara buat CV perusahaan tentunya harus ada nama dari CV tersebut. bahkan hal lain merupakan tahap awal dalam pembuatan CV perusahaan. Namun, menyiapkan nama tidak berarti CV anda sudah resmi berdiri. Karena harus melalui beberapa prosedur dalam pembuatannya. Sehingga dapat dikatakan CV anda resmi berdiri secara hukum. Berikut ini beberapa prosedur yang bisa anda ketahui sebelum anda bekerja sama dengan jasa buat CV tersebut.
Akta pendirian
Untuk prosedur pertama yang perlu anda lakukan yaitu persiapkan akta pendirian dari CV perusahaan anda memang sangat perlu anda perhatikan. Untuk bisa mendapatkan akta pendirian sebuah CV perusahaan, anda bisa melalui notaris. Caranya yaitu anda datang ke notaris dengan membawa beberapa persyaratan serta mendaftarkan pembuatan akta perusahaan tersebut.
Surat domisili usaha
Sedangkan untuk prosedur yang kedua yaitu persiapkan beberapa dokumen untuk bisa mendapatkan surat domisili CV perusahaan anda. di tempat berdirinya CV anda. maka surat domisili usaha ini dapat anda peroleh dari pemerintah yang berada di lingkungan CV anda tersebut. untuk lebih lengkapnya, maka anda dapatkan mencari tahu apa saja syarat dalam pembuatan domisili usaha.
Mengurus nomor pokok wajib pajak
Anda juga perlu membuat nomor pokok wajib pajak di kantor pajak yang berada di lingkungan sekitar perusahaan anda berdiri. Kemudian ketika anda mendaftar. Maka anda juga akan mendapatkan kartu Nomor pokok wajib pajak sebagai beberapa hal yang harus disiapkan untuk melengkapi cara membuat CV perusahaan tersebut.
Surat pengukuhan pengusaha kena pajak atau SP-PKP
Cara buat CV perusahaan yang selanjutnya yaitu dengan memiliki SP-PKP. Proses ini memang bertahap setelah anda mendapatkan NPWP. Sehingga buatlah terlebih dahulu pengajuan surat pengukuhan pengusaha kena pajak ketika anda ingin mengajukan nomor pokok wajib pajak tersebut.
Menggunakan surat Izin Usaha
Untuk langkah selanjutnya yaitu anda bisa menggunakan surat usaha izin usaha. Pentingnya dalam menggunakan surat izin usaha. Hal tersebut disebabkan karena CV juga merupakan sebuah perusahaan komersial. Sehingga anda juga perlu mempersiapkan SIU.
Mendaftar ke pengadilan negeri
Cara membuat CV perusahaan yang terakhir adalah dengan mengajukan beberapa pendaftaran ke pengadilan negeri. Hal tersebut perlu anda lakukan yang digunakan untuk membuat persiapan CV perusahaan anda dicatat dalam dokumen pemerintah.
Demikian beberapa hal yang bisa anda ketahui mengenai cara buat CV yang bisa anda ketahui. Jika anda ingin mendapatkan jasa pembuatan CV terbaik dan terpercaya. Maka akan lebih baik jika anda segera memperhatikan beberapa ulasan kami berikut ini mengenai jasa pembuatan CV dan pengurusan izin usaha terbaik.
Cari Jasa Buat CV di BATU Terbaik? Di Sini Tempatnya!
Itulah beberapa prosedur yang perlu anda lengkapi jika anda ingin buat CV perusahaan. Apakah anda merasa kesulitan atau belum mengetahui seperti apa?. Jika anda merasa kesulitan, maka akan lebih baik jika anda mempercayakan jasa buat CV di BATU di www.popjasa.id yang mana anda tidak perlu bingung dengan Cara buat CV cepat di BATU yang sangat rumit itu. Sebab hanya dengan mempercayakan nya pada jasapengurusanizinusaha.com. Maka anda bisa mendapatkan berbagai jenis surat izin usaha yang pasti juga terpercaya. Yang mana kami memiliki tenaga yang sudah ahli, profesional dan berkompeten. Sehingga jika anda ingin bekerja sama dengan kami. maka anda tidak perlu khawatir. Sebab hanya di jasapengurusanizinusaha.com anda bisa mendapatkan CV perusahaan cepat dan dengan prosedur yang tepat. mengenai biaya, anda tidak perlu khawatir. Sebab kami selalu memastikan semua anda dapatkan dengan harga terjangkau. Akan tetapi tetap dengan prosedur yang tepat dan terpercaya.


content:
Mahjong adalah game berbasis ubin. Ini menguji indera orang dan membutuhkan pemikiran cepat. Untuk seseorang yang mahir di Mahjong, mereka harus waspada dan dapat menemukan pola dengan sangat cepat. Bermain Mahjong dengan uang sungguhan itu mengasyikkan karena memberikan tantangan yang sangat dibutuhkan para profesional dan tentu saja aspek uang. Game ini sangat populer di kalangan orang yang bermain menggunakan uang sungguhan karena beberapa aturan yang terlibat. Permainan ini dapat dipelajari dalam beberapa menit dan seorang pemula memiliki kemungkinan tinggi untuk memenangkan beberapa permainan jika mereka waspada dan dapat melihat polanya.
Pentingnya Memiliki Anggaran
Memiliki anggaran sangat penting dalam apa pun yang dilakukan seseorang. Anggaran memungkinkan orang untuk mencapai sebagian besar dari apa yang mereka inginkan dengan uang yang mereka miliki dan mengalihkan dana lain ke hal-hal lain yang diperlukan. Tidak memiliki anggaran berarti bahwa pada titik tertentu seseorang harus mencelupkan ke dalam dana yang dimaksudkan untuk hal-hal penting seperti sewa, transportasi dan makanan. Demikian pula, dengan judi prinsipnya sama. Anggaran ketat harus ditetapkan dan harus diikuti. Jika ini dilakukan akan membatasi kemungkinan seseorang bangkrut dan harus meminjam uang dari orang.
Taruhan Mahjong
Jauh di lubuk hati kita semua tahu orang seperti apa kita. Kami tahu apa yang bekerja untuk kami dan kapan kami menuju level dan kami juga tahu apa yang menekan tombol kami dan membuat kami berperilaku sangat ceroboh. Penting untuk memikirkan hal-hal ini sebelum bermain dalam kondisi tertentu. Jika amarah, alkohol atau orang banyak adalah pemicu Anda untuk membuat keputusan yang buruk, ini harus dihindari. Masalah bermain game pemicu atau yang taruhannya di atas anggaran adalah bahwa keputusan yang akan menyusul adalah keputusan yang belum dipertimbangkan dengan cermat. Banyak orang kehilangan banyak uang dengan cara ini.
Taruhan Online
Taruhan online telah menguasai dunia. Sebelumnya orang harus mengendarai semua cara untuk bertaruh rumah untuk ini, tetapi sekarang dengan beberapa klik pada laptop atau smartphone orang bisa mendapatkan akses ke ribuan situs kasino. Karena banyak situs kasino yang sah menjalankan bisnis secara profesional dan adil, ada juga ribuan situs yang tidak bermain adil dan satu-satunya tujuan mereka adalah menipu orang-orang atas dana mereka. Situs-situs ini selalu memiliki peluang sangat tinggi yang terlalu bagus untuk menjadi kenyataan. Sangat penting untuk hanya bermain menggunakan situs web tepercaya dan mapan.
Bermain Dengan Mata Uang Yang Berbeda
Mata uang bisa sulit dipahami. Sebagian besar orang tidak mengetahui nilai tukar karena mereka tidak berurusan langsung dengan mata uang tersebut. Orang lain mungkin memahami mata uang tetapi keterampilan matematika mereka tidak sehebat yang seharusnya. Sangat penting saat bermain Mahjong atau game online lainnya untuk melakukannya dalam mata uang yang mudah digunakan. Mata uang berfluktuasi sepanjang waktu sehingga orang mungkin berpikir mereka menghasilkan untung padahal sebenarnya mereka merugi. Menggunakan mata uang seseorang biasanya yang terbaik karena mudah untuk memahami nilai-nilai yang dirujuk.


content:
Setelah penantian yang cukup lama, petualangan Shiroe dan Akatsuki dalam game MMORPG Elder Tale akhirnya berlanjut ke musim ketiga.
Tayang Perdana di Website
Dilansir dari Crunchyroll, musim ketiga ini telah dikonfirmasi melalui cuitan dari akun resmi NHK Anime World. Selain itu, mereka juga telah menjadwalkan penayangan episode perdananya, yaitu pada tanggal 31 Januari 2021 di situs resmi mereka, NHK-E. Cerita dari musim ketiga ini nantinya akan berfokus ke Round Table Collapse.
【「ログ・ホライズン　円卓崩壊」PV第1弾を公開!!】
主人公シロエのメガネ芸もブランクを感じさせない(？)切れ味は健在！
おなじみアカツキ、直継＆てとら、にゃん太班長にレイネシア姫、さらに大陸組のカナミにクラスティ…みんな相変わらず元気そうですね♪#loghorizonhttps://t.co/nhUXc44HLu
— NHKアニメ (@nhk_animeworld) September 23, 2020
Ditunda Akibat Pandemi
Sebelumnya, anime ini telah dijadwalkan tayang pada bulan Oktober nanti. Namun, akibat pandemi Covid-19 ini banyak dari studio produksi anime yang terdampak. Akhirnya, studio DEEN yang ikut andil dalam penggarapan dari sekuel ini harus menunda pengerjaan anime ini untuk sementara waktu. Setelah kondisi semakin kondusif, kru yang juga ikut dalam pembuatan musim pertama dan kedua ini dapat melanjutkan produktivitasnya kembali.
Sinopsis Singkat
Dan berikut ini adalah kutipan dari NHK mengenai seri ini:
"Suatu hari, puluhan ribu pemain atau Petualang terjebak di dunia game online populer Elder Tale! Orang-orang bingung di dunia yang berbeda di mana monster dan sihir ada secara realistis, dan kota petualang, Akihabara, mengalami kekacauan.
Seorang pemuda, Shiroe, yang tidak hebat dalam berinteraksi dengan orang-orang, adalah salah satu dari para petualang itu dan memutuskan untuk membentuk guild "Log Horizon" dengan partainya, Akasuki, dan Nyanta. Selanjutnya, dia menyerukan persatuan petualang untuk menggunakan kebijaksanaannya sendiri sebagai senjata, meluncurkan "Konferensi Meja Bundar", dan memulihkan perdamaian dan stabilitas kota.
Berpusat di sekitar Aliansi Meja Bundar, interaksi dengan penduduk asli dunia game, The Earthlings, telah dimulai dengan para petualang, bangsawan, pedagang, warga umum, semuanya bekerja sama untuk mencapai diplomasi.
Namun, para petualang hanya memiliki satu tahun dari "malapetaka" yang telah ditiup dari negara lain. Akihabara, yang menikmati kemakmuran sesaat, harus berurusan dengan spesies baru monster "Tenwazawai" yang menyerang kota dan kaum bangsawan dari timur dan barat yang bertengkar satu sama lain.
Api ketidakpuasan terus membara di antara guild, dengan perebutan kekuasaan, perbedaan, dan spekulasi yang terjadi di antara para petualang.
Akhirnya, krisis kritis akan datang ke meja bundar, simbol persatuan dengan para petualang"
Selain penayangan sekuel Log Horizon, acara yang juga diadakan oleh NHK dalam waktu dekat ini adalah SONGS OF TOKYO FESTIVAL 2020 yang MedForians dapat cek lebih lengkap di link berikut ini.
Tag
Pop Kultur
Yoan Fernanda
Seorang penggemar Pop Culture, baik Western, Korea, maupun Jepang. Dan seorang Petrolhead, fans berat Subaru #FL4TISJUSTICE

warc-identified-content-language: ind,jpn,eng

label: ja