Skip to content

Instantly share code, notes, and snippets.

@isopen
Last active October 21, 2025 07:29
Show Gist options
  • Select an option

  • Save isopen/25c4829daffb3880a32fac1f85f5f888 to your computer and use it in GitHub Desktop.

Select an option

Save isopen/25c4829daffb3880a32fac1f85f5f888 to your computer and use it in GitHub Desktop.
gas_tdjson_example.s
# TDLib Minimal Linux Client in x86-64 GNU Assembler
#
# as -o gas_tdjson_example.o gas_tdjson_example.s
# gcc -o gas_tdjson_example gas_tdjson_example.o -ldl -no-pie
# ./gas_tdjson_example
.section .data
# Error messages
lib_error: .asciz "Error: libtdjson.so not found\n"
client_error: .asciz "Error: Failed to create client\n"
input_error: .asciz "Error reading input\n"
receive_error: .asciz "Error in receive function\n"
# Function names
create_name: .asciz "td_json_client_create"
send_name: .asciz "td_json_client_send"
receive_name: .asciz "td_json_client_receive"
destroy_name: .asciz "td_json_client_destroy"
execute_name: .asciz "td_json_client_execute"
# Library name
lib_name: .asciz "libtdjson.so"
# Prompts
phone_prompt: .asciz "Enter phone number (international format): "
code_prompt: .asciz "Enter authentication code: "
password_prompt: .asciz "Enter password: "
auth_success: .asciz "Authorization successful!\n"
auth_wait: .asciz "Waiting for authorization...\n"
# JSON messages
params_msg: .asciz "{\"@type\":\"setTdlibParameters\",\"database_directory\":\"td_data\",\"use_message_database\":true,\"api_id\":94575,\"api_hash\":\"a3406de8d171bb422bb6ddf3bbd800e2\",\"system_language_code\":\"en\",\"device_model\":\"AsmClient\",\"application_version\":\"1.0\"}"
verbosity_msg: .asciz "{\"@type\":\"setLogVerbosityLevel\",\"new_verbosity_level\":2}"
close_msg: .asciz "{\"@type\":\"close\"}"
newline: .asciz "\n"
# Authorization states
auth_wait_phone: .asciz "authorizationStateWaitPhoneNumber"
auth_wait_code: .asciz "authorizationStateWaitCode"
auth_wait_password: .asciz "authorizationStateWaitPassword"
auth_ready: .asciz "authorizationStateReady"
# Format strings
fmt_phone: .asciz "{\"@type\":\"setAuthenticationPhoneNumber\",\"phone_number\":\"%s\"}"
fmt_code: .asciz "{\"@type\":\"checkAuthenticationCode\",\"code\":\"%s\"}"
fmt_password: .asciz "{\"@type\":\"checkAuthenticationPassword\",\"password\":\"%s\"}"
.section .bss
# Handle pointers
.lcomm lib_handle, 8
.lcomm client_handle, 8
# Function pointers
.lcomm create_func, 8
.lcomm send_func, 8
.lcomm receive_func, 8
.lcomm destroy_func, 8
.lcomm execute_func, 8
# Buffers
.lcomm input_buffer, 256
.lcomm phone_buffer, 32
.lcomm code_buffer, 16
.lcomm password_buffer, 64
.lcomm json_buffer, 1024
.lcomm auth_state, 8
.section .text
.globl main
.extern dlopen
.extern dlsym
.extern printf
.extern sleep
.extern exit
.extern fgets
.extern stdin
.extern strstr
.extern sprintf
.extern strlen
.extern putchar
.extern usleep
.extern fflush
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
# Load TDLib library
movq $lib_name, %rdi
movq $1, %rsi
call dlopen
testq %rax, %rax
jz .dl_error
movq %rax, lib_handle(%rip)
# Get function addresses
movq lib_handle(%rip), %rdi
movq $create_name, %rsi
call dlsym
movq %rax, create_func(%rip)
movq lib_handle(%rip), %rdi
movq $send_name, %rsi
call dlsym
movq %rax, send_func(%rip)
movq lib_handle(%rip), %rdi
movq $receive_name, %rsi
call dlsym
movq %rax, receive_func(%rip)
movq lib_handle(%rip), %rdi
movq $destroy_name, %rsi
call dlsym
movq %rax, destroy_func(%rip)
movq lib_handle(%rip), %rdi
movq $execute_name, %rsi
call dlsym
movq %rax, execute_func(%rip)
# Create TDLib client
movq create_func(%rip), %rax
call *%rax
testq %rax, %rax
jz .client_error
movq %rax, client_handle(%rip)
# Set log verbosity
movq client_handle(%rip), %rdi
movq $verbosity_msg, %rsi
movq execute_func(%rip), %rax
call *%rax
# Set TDLib parameters
movq client_handle(%rip), %rdi
movq $params_msg, %rsi
movq send_func(%rip), %rax
call *%rax
# Authorization loop
xorq %r12, %r12
movq $0, auth_state(%rip)
movq $50000, %rdi
call usleep
.auth_loop:
movq client_handle(%rip), %rdi
xorq %rsi, %rsi
movq receive_func(%rip), %rax
call *%rax
testq %rax, %rax
jz .no_message
# Process message
movq %rax, %rdi
call process_message
cmpq $1, %r12
je .auth_complete
.no_message:
# Check if we need to request input
cmpq $1, auth_state(%rip) # wait_phone
je .request_phone
cmpq $2, auth_state(%rip) # wait_code
je .request_code
cmpq $3, auth_state(%rip) # wait_password
je .request_password
movq $10000, %rdi
call usleep
jmp .auth_loop
.request_phone:
movq $phone_prompt, %rdi
call printf
xorq %rdi, %rdi
call fflush
# Read phone number
movq $phone_buffer, %rdi
movq $32, %rsi
movq stdin(%rip), %rdx
call fgets
testq %rax, %rax
jz .input_error
# Remove newline
movq $phone_buffer, %rdi
call remove_newline
# Create JSON for phone number
movq $json_buffer, %rdi
movq $fmt_phone, %rsi
movq $phone_buffer, %rdx
call sprintf
# Send to TDLib
movq client_handle(%rip), %rdi
movq $json_buffer, %rsi
movq send_func(%rip), %rax
call *%rax
movq $0, auth_state(%rip)
movq $10000, %rdi
call usleep
jmp .auth_loop
.request_code:
movq $code_prompt, %rdi
call printf
xorq %rdi, %rdi
call fflush
# Read code
movq $code_buffer, %rdi
movq $16, %rsi
movq stdin(%rip), %rdx
call fgets
testq %rax, %rax
jz .input_error
# Remove newline
movq $code_buffer, %rdi
call remove_newline
# Create JSON for code
movq $json_buffer, %rdi
movq $fmt_code, %rsi
movq $code_buffer, %rdx
call sprintf
# Send to TDLib
movq client_handle(%rip), %rdi
movq $json_buffer, %rsi
movq send_func(%rip), %rax
call *%rax
movq $0, auth_state(%rip)
movq $10000, %rdi
call usleep
jmp .auth_loop
.request_password:
movq $password_prompt, %rdi
call printf
xorq %rdi, %rdi
call fflush
# Read password
movq $password_buffer, %rdi
movq $64, %rsi
movq stdin(%rip), %rdx
call fgets
testq %rax, %rax
jz .input_error
# Remove newline
movq $password_buffer, %rdi
call remove_newline
# Create JSON for password
movq $json_buffer, %rdi
movq $fmt_password, %rsi
movq $password_buffer, %rdx
call sprintf
# Send to TDLib
movq client_handle(%rip), %rdi
movq $json_buffer, %rsi
movq send_func(%rip), %rax
call *%rax
movq $0, auth_state(%rip)
movq $10000, %rdi
call usleep
jmp .auth_loop
.auth_complete:
movq $auth_success, %rdi
call printf
# Main loop
movq $100, %r13
.main_loop:
# Receive messages
movq client_handle(%rip), %rdi
xorq %rsi, %rsi
movq receive_func(%rip), %rax
call *%rax
testq %rax, %rax
jz .no_msg_main
# Print message
movq %rax, %rdi
call printf
movq $newline, %rdi
call printf
.no_msg_main:
movq $50000, %rdi
call usleep
decq %r13
jnz .main_loop
.cleanup:
# Send close command
movq client_handle(%rip), %rdi
movq $close_msg, %rsi
movq send_func(%rip), %rax
call *%rax
movq $50000, %rdi
call usleep
# Destroy client
movq client_handle(%rip), %rdi
movq destroy_func(%rip), %rax
call *%rax
# Exit
xorq %rdi, %rdi
call exit
.dl_error:
movq $lib_error, %rdi
call printf
movq $1, %rdi
call exit
.client_error:
movq $client_error, %rdi
call printf
jmp .cleanup
.input_error:
movq $input_error, %rdi
call printf
jmp .cleanup
process_message:
pushq %rbp
movq %rsp, %rbp
pushq %r12
pushq %r13
movq %rdi, %r12
movq %r12, %rdi
movq $auth_wait_phone, %rsi
call strstr
testq %rax, %rax
jnz .wait_phone
movq %r12, %rdi
movq $auth_wait_code, %rsi
call strstr
testq %rax, %rax
jnz .wait_code
movq %r12, %rdi
movq $auth_wait_password, %rsi
call strstr
testq %rax, %rax
jnz .wait_password
movq %r12, %rdi
movq $auth_ready, %rsi
call strstr
testq %rax, %rax
jnz .auth_ready_done
jmp .done
.wait_phone:
movq $1, auth_state(%rip)
jmp .done
.wait_code:
movq $2, auth_state(%rip)
jmp .done
.wait_password:
movq $3, auth_state(%rip)
jmp .done
.auth_ready_done:
movq $1, %r12
movq $0, auth_state(%rip)
.done:
popq %r13
popq %r12
popq %rbp
ret
remove_newline:
pushq %rbp
movq %rsp, %rbp
movq %rdi, %rcx
.find_end:
cmpb $0, (%rcx)
je .check_newline
incq %rcx
jmp .find_end
.check_newline:
decq %rcx
cmpb $10, (%rcx)
jne .end
movb $0, (%rcx)
.end:
popq %rbp
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment