1 pontos por GN⁺ 2023-10-16 | 1 comentários | Compartilhar no WhatsApp
  • O Lotus 1-2-3, uma planilha proprietária de 30 anos, passou a rodar nativamente no Linux após a recuperação acidental de materiais e hacking de binários, mesmo que o sistema não existisse na época do lançamento
  • A descoberta do SDK de add-ins LPL dado como perdido e do Lotus 1-2-3 for UNIX em backups de BBS dos anos 1990 tornou possível compilar plugins de exemplo e analisar os binários UNIX
  • A distribuição UNIX incluía o objeto COFF Intel 80386 compactado 123.o, e cerca de 20.000 símbolos e informações de debug revelaram a estrutura interna
  • O port não se resumiu a converter COFF para ELF; foi preciso contornar as diferenças de ABI de chamadas de sistema e estruturas entre Linux e UNIX com coffsyrup e funções wrapper
  • Atualmente o port roda sem travar e está 100% utilizável, mas ainda restam alguns problemas e o port do driver de terminal, então a versão DOS em emulação ainda parece melhor

O ponto de partida para levar um app proprietário de 30 anos ao Linux

  • O Lotus 1-2-3 permanecia como um abandonware de 30 anos, mas várias descobertas e hacks tornaram possível um port nativo para Linux
  • O alvo do port é o clássico Lotus 1-2-3 R3, embora o próprio Lotus 1-2-3 tenha recebido lançamentos até 2002
  • O projeto começou a partir da manutenção do driver lotusdrv, feito para que o Lotus 1-2-3 funcione bem em sistemas modernos
    • A API do driver foi entendida por engenharia reversa, e os drivers existentes funcionam bem em sistemas modernos

O SDK LPL perdido e os backups de BBS

  • O Lotus 1-2-3 foi projetado para ser expandido com plugins, ou add-ins, mas eles precisavam ser escritos em uma linguagem especial chamada LPL
  • O compilador LPL e o SDK haviam desaparecido, e a Lotus não distribuía o SDK gratuitamente: ele era vendido por US$ 395
  • O SDK foi recuperado em forma de warez por meio de um ex-sysop que guardava backups em fita de sistemas BBS dos anos 1990
    • O ADK recuperado pode ser baixado em 123DADK.ZIP
    • Um programa de exemplo em LPL foi publicado como modern.pl
  • Esses mesmos backups de BBS também continham uma cópia warez do Lotus 1-2-3 for UNIX, amplamente considerada perdida

Análise das imagens de disco do Lotus 1-2-3 for UNIX

  • A versão UNIX sobreviveu em um conjunto de arquivos TD0 de 123UNIX1.TD0 até 123UNIX5.TD0
  • Foi confirmado que TD0 é um formato antigo de imagem de disco compactada dos anos 1980, e a conversão para imagem de disco raw foi feita com samdisk
  • Entre as imagens convertidas, a primeira era um tar archive, e as demais eram archives cpio ASCII no formato pre-SVR4 ou odc
  • O conjunto completo das imagens de disco foi enviado para o Internet Archive
  • Depois da descompactação, surgiram em lotus/123.v10 o executável, ajuda, keymaps, dados de drivers de impressora e vídeo, arquivos de exemplo, manuais e mais
    • A estrutura total tinha cerca de 35 diretórios e 338 arquivos

A pista decisiva: 123.o

  • No diretório sysV386/lib, foi encontrado um arquivo grande dividido em 123.o.z_1 e 123.o.z_2
  • Após juntar as duas partes e descompactar, 123.o foi identificado como um arquivo objeto COFF Intel 80386
    • arquivo objeto sem strip
    • 5 seções
    • offset de símbolos 0x1efbdc
    • 19.755 símbolos

      • tamanho do optional header: 28
      • Esse arquivo incluía símbolos privados e informações de debug, o que ajudou muito a entender a estrutura interna do Lotus 1-2-3
      • A resposta recebida em alt.folklore.computers sugeriu que esse arquivo não foi incluído por engano
      • Como o dlopen() não era amplamente usado no UNIX do início dos anos 1990, é provável que tenha sido um objeto parcialmente ligado para extensão de recursos e relinkedição

A estrutura interna revelada pelas informações de debug

  • A versão UNIX era próxima de um port direto do código-fonte da versão DOS, então a maior parte do funcionamento era igual
  • As informações de debug incluídas esclareceram várias dúvidas sobre o interior do Lotus 1-2-3
  • Para melhorar a saída de gráficos, queria-se colocar um hook no rasterizador a partir do driver, mas era difícil entender o funcionamento apenas com a documentação
  • Com as informações de debug, foi possível descobrir que o rasterizador gera dinamicamente pequenos programas em bytecode, que o motor gráfico interpreta
  • Depois de identificar os opcodes, isso passou a poder ser desmontado e alterado em raster.c para melhorar a saída

Convertendo de COFF para ELF

  • O objcopy consegue converter arquivos objeto COFF para o formato ELF usado no Linux
  • O comando objcopy -I coff-i386 -O elf32-i386 123.o 123elf.o foi usado para converter 123.o em 123elf.o
  • O resultado foi identificado como ELF 32-bit LSB relocatable, Intel 803386, version 1 (SYSV), not stripped
  • Segundo o objdump, o horário de compilação do arquivo objeto original era 8 de setembro de 1990 às 06:23:50, ou seja, antes da primeira versão do Linux

Lidando com as diferenças de ABI entre Linux e UNIX

  • O primeiro problema era que Linux e UNIX não usam interfaces de chamadas de sistema compatíveis entre si
  • A versão UNIX usava a interface lcall7; por exemplo, open() fazia uma chamada de callgate no formato call 0x7:0x0
  • Como o Linux não dá suporte a esse callgate, a execução travava se fosse mantido como estava
    • O Linux já teve suporte de compatibilidade para lcall7 e lcall27, mas isso não existe mais
  • O objetivo era eliminar essas chamadas e redirecionar tudo para passar pela glibc

Relocação e coffsyrup

  • A tentativa inicial foi remover o símbolo com objcopy --strip-symbol open, mas o objcopy recusou porque open era usado em uma relocation
  • Um arquivo objeto relocável inclui referências simbólicas e informações de relocação para funcionar independentemente do endereço em que for carregado
  • Para remover um símbolo, também é preciso alterar junto a informação de relocação que o referencia
  • Para isso, foi criada a pequena ferramenta coffsyrup
    • Ela consegue remover símbolos COFF que o objcopy se recusa a retirar
    • Como exemplo, ela localiza e trata o símbolo open e as relocations associadas

Funções UNIX que não são binariamente compatíveis

  • Muitas funções UNIX padrão são compatíveis em nível de código-fonte, mas não binariamente compatíveis
  • Um exemplo representativo é struct stat
    • O mesmo código C pode ser compilado em várias famílias UNIX
    • Mas o arquivo objeto compilado pode quebrar em outro sistema por diferenças no tamanho de struct stat ou no offset de st_size
  • As principais funções que precisaram ser tratadas foram stat(), times(), uname(), fcntl(), ioctl() e outras
  • A abordagem foi renomear símbolos com objcopy, marcá-los como undefined com coffsyrup e escrever funções wrapper que convertem estruturas Linux em estruturas UNIX
  • termios foi um obstáculo particularmente grande, porque os detalhes do comportamento variam de forma sutil entre sistemas UNIX e não são compatíveis, o que dificultou o debug

Verificação de licença e resultado da execução

  • Depois de vários hacks, o programa passou a rodar sem travar, mas não funcionava sem uma licença
  • Ao colocar um breakpoint em exit(), descobriu-se que o símbolo interno responsável por validar a licença era lic_init()
  • A análise do código no IDA mostrou que a checagem de licença procura o arquivo LICENSE.000 e verifica se a data de expiração, o nome do usuário e o nome do sistema batem com os valores informados pelo sistema
  • No fim, o Lotus 1-2-3 foi portado para um novo sistema operacional: o Linux
  • O estado atual é o seguinte
    • roda sem travar
    • 100% utilizável

      • alguns problemas ainda precisam ser ajustados
      • o port do driver de terminal ainda está pendente
      • por enquanto, a versão DOS rodando em emulação ainda parece melhor, mas isso pode ser corrigido
      • o código do port está disponível no github

1 comentários

 
GN⁺ 2023-10-16
Opiniões no Hacker News
  • É quase inacreditável que tenham recuperado uma cópia warez do SDK a partir de um backup em fita de um antigo sistema BBS e ainda compilado até o plugin de exemplo
    Isso me lembrou Why History Needs Software Piracy

    • Eu queria criar um arquivo de preservação de longo prazo reunindo manuais, atualizações de firmware, drivers e utilitários de sintetizadores, equipamentos Eurorack etc. vendidos atualmente
      Esses equipamentos são hardwares que continuarão existindo por décadas, então haveria grande valor público em ter um repositório centralizado e duradouro que toda a comunidade pudesse usar, indo além de cada fabricante guardar tudo em sua própria nuvem pessoal
      Também pensei em distribuir o arquivo todos os anos, ou vender um archival Blu-ray em mídia física capaz de durar uns 100 anos
      Assim, quando alguém precisasse recuperar o firmware corrompido de um módulo Eurorack com DSP baseado em ARM, a probabilidade de alguém ter o último e raro arquivo .bin necessário ficaria próxima de 1
  • Meu pai guardava um monte de arquivos Lotus 1-2-3 importantes em um notebook secundário com uma versão antiga do Windows, e às vezes precisava abri-los, então aquela situação era bem preocupante
    Recentemente descobri que o LibreOffice consegue converter arquivos Lotus para ODF/ODS, até pela linha de comando, e converti tudo com um script bash simples
    Fiz upload em lote dos arquivos convertidos para um Nextcloud com Collabora, criei uma conta para meu pai e expliquei o uso básico; agora ele consegue ver os arquivos online, e eles também entram na rotina normal de backup do servidor
    Sou muito grato a arqueólogos de dados como o OP e aos contribuidores do LibreOffice

    • Fico bem curioso para saber que tipo de arquivos são, para ainda serem importantes depois de tanto tempo
  • Lembro de quando eu tinha 7 anos e pedi um Nintendo; meu pai comprou em vez disso um PC 286 com Lotus 1-2-3 e a aventura de texto Indiana Jones

    • No Computer Museum de Boston, achei a LISP Machine incrível e disse que queria uma, mas acabei ganhando um Commodore 64
      Por isso minha primeira linguagem foi BASIC, não LISP, e pretendo culpar essa tragédia por todos os fracassos da minha vida, sem aceitar contestações
    • Implorei por um NES, mas meu pai comprou um C64, dizendo “este é melhor, você vai entender depois”, e isso acabou mudando minha vida
    • Eu queria um BBC Micro, mas ganhei um ZX Spectrum, e no fim ele foi muito melhor para me fazer criar interesse por programação
      Mesmo que o Spectrum já estivesse em declínio naquela época
    • Ganhei um Apple IIgs e Leisure Suit Larry, mas nem eu nem meu irmão mais velho conseguíamos acertar de forma confiável as respostas às perguntas de verificação de idade no início
  • Estou fazendo um trabalho parecido, mas acrescentando uma etapa que primeiro transforma partes do programa em arquivos-objeto
    Assim, não fico preso apenas aos arquivos-objeto existentes que sobreviveram, embora seja necessária certa engenharia reversa para fazer funcionar
    Fiz uma prova de conceito com aln, o linker do Atari Jaguar, separando um executável Linux x86 a.out em arquivos-objeto ELF e depois fazendo o link novamente como um executável ELF x86, contornando as diferenças de ABI
    https://forums.atariage.com/topic/354341-porting-the-original-atari-jaguar-sdk-to-elf/

  • Foi interessante em vários aspectos
    O processo de levar um binário UNIX para um binário Linux sem código-fonte, sem o compilador original e sem a linguagem original pareceu muito legal; esse é o tipo de conteúdo que combina com o HN
    Também serve para lembrar que, em 2023, a Usenet ainda é usada para coisas além da simples distribuição de arquivos rar
    E também traz à memória a cultura dos BBS antes da popularização da internet, quando entusiasmo e ótimas distribuições shareware chegavam ao público

    • Parece que o espírito dos BBS está voltando
      Ainda mais vendo o colapso do Twitter e de outras redes sociais; a Geração Z mais velha está mergulhando no retrô dos anos 80 e 90 e até baixando sons de negociação de modem como toque de celular
      Meu sobrinho de 23 anos fez isso recentemente, e obras como American Horror Story e Stranger Things continuam alimentando essa nostalgia
      A velha máxima de que, se você esperar tempo suficiente, tudo volta à moda acaba estando certa
  • Também houve uma boa discussão em maio de 2022 do ano passado
    https://news.ycombinator.com/item?id=31455968

  • O site https://scenelist.org/ linkado neste excelente texto foi exatamente a bomba de nostalgia de que eu precisava esta manhã
    É uma ótima viagem ao passado, recomendo muito

  • Links relacionados
    Lotus 1-2-3 for Linux - https://news.ycombinator.com/item?id=35807639 - maio de 2023, 73 comentários
    Lotus 1-2-3 - https://news.ycombinator.com/item?id=35872758 - maio de 2023, 117 comentários
    Lotus 1-2-3 For Linux - https://news.ycombinator.com/item?id=31455968 - maio de 2022, 83 comentários
    Lotus 1-2-3 arbitrary resolution - https://news.ycombinator.com/item?id=26316637 - março de 2021, 123 comentários

  • Eu tinha esquecido completamente do 1-2-3, apesar de tê-lo usado rapidamente no ano passado
    O binário 123 ainda roda muito bem no Linux, e é um feito e tanto que um software desaparecido há tanto tempo simplesmente funcione

  • Sempre quis algo assim. Como não uso muito fontes ou imagens em planilhas, uma planilha baseada em terminal é perfeita
    Fico feliz que finalmente tenha surgido, e seria ótimo se fosse portada para Mac e Windows