# Não Manifesto

Caloni, 2008-10-01 <quotes> <self> <now> [up] [copy]
É possível ficar consciente do Não Manifesto em todas as ocasiões.
É da Fonte que retiramos a energia vital (“Nem só de pão vive o homem”).
O Não Manifesto não nos liberta a menos que sejamos capazes de chegar a ele de modo consciente (“Conheceremos a verdade, e a verdade nos libertará”).
A paralisação do pensamento é um portal para o Não Manifesto.
A entrega é um portal para o Não Manifesto.
Tolle, Eckhart (O Poder do Agora, 1997)

# O que acontece com um programador com pressa

Caloni, 2008-10-05 <archive> [up] [copy]

Eu já sabia, mas é lógico que não ia falar.

Há um tempo atrás um rapaz me pediu para responder uma série de questões sobre a carreira de programador C++. Era um rapaz empolgado com a idéia de aprender a linguagem em seis meses, com um roteiro, cronograma e um blogue recém-criados.

Como quase toda uma geração do imediatismo, aconteceu o inevitável: o blogue já não é atualizado há quase dois meses e toda aquela empolgação do começo deve ter virado fumaça assim que a pessoa vira a esquina e aparece uma coisa nova para fazer. E daí surgem as desculpas, o blá-blá-blá de todos aqueles que nunca têm tempo.

Eu sou um deles, mas de vez em quando atualizo esse meu espacinho =)

Na experiência de vida que tenho com todas aquelas idéias mirabolantes que as pessoas possuem de fazer alguma coisa, seja um software, aprender algo novo, ou até criar uma rotina qualquer, eu diria que quase todas, se não todas, falharam.

É natural que no começo, quando a idéia brota, e mais idéias formentam a idéia original, o empolgamento nos dá a falsa impressão que podemos fazer isso facilmente, e que é só planejar, ter vontade e ir em frente que conseguimos. É claro que toda essa impressão muda com o passar do tempo, principalmente para aquelas pessoas que possuem muitas idéias em muito pouco tempo, algo que acontece bastante com programadores, mas que em geral afeta todo mundo.

Em se tratando de software, a primeira coisa que deve ser feita, sempre, é planejar as tarefas visíveis a serem feitas para esboçar um panorama possível para o futuro do projeto. Eu disse possível no sentido de realizável.

O segundo passo é esquecer esse negócio de realizável, cair na real e encarar os fatos: o mundo não é perfeito. Comece a colocar defeitos no cronograma, tentar imaginar o que vai sair errado e, principalmente, conhecer você mesmo e as pessoas envolvidas para ter a real expectativa do que pode ser feito em quanto tempo.

Após jogar água fria o suficiente (às vezes são necessários muitos baldes) sobre suas idéias novas e excitantes, temos um panorama um pouco mais preciso, mais realista e, agora sim, passível de ser feito e acontecer de verdade.

Só que ainda não acabou.

É claro que isso tudo é o começo do projeto. Após a primeira semana, o primeiro mês, o segundo mês e o segundo semestre as atividades devem ser revistas e reprojetadas. Mais uma vez entra a regrinha da água fria. Não é porque deu errado no começo que não pode dar mais errado ainda no final.

Esse pequeno chamado foi apenas um reforço do apelo que Rodrigo Strauss fez em nosso último encontro de C++. Nosso grupo precisa de mais pessoas que escrevam algo. Portanto, façam blogues, mas não os deixem desgarrados!

// Comments

2008-10-20 Bruno Moreira Guedes:

Olá!! Muito bom o POST!!

Gostaria de dizer que você me descreveu ao falar das "pessoas que tem muitas idéias em um intervalo curto de tempo".

O que tenho feito ultimamente é tentar filtrá-las ao máximo. Estou montando um negócio próprio, e tenho tido lutas diárias contra minha própria mente em função de realizar meus planos.

Mas não digo que muitas idéias tenha sido algo ruim pra mim. Isso me fez adquirir os mais diversos conhecimentos sobre uma infinidade de assuntos, e estes sempre "voltam a tona" quando preciso de algo relacionado.

Porém, para viver no mundo real, precisamos deixar isso no ponto em que parou, e apenas reaproveitar o que já fomos atrás.

Abraços!! Vou linkar este post no meu blog.


2009-01-13 Daniel Quadros:

Menos de uma semana para acabar o prazo do rapaz... O erro foi tentar aprender a programar em 6 meses, quando todo mundo sabe que são precisos 10 anos!


2009-01-14 Caloni:

Pois, é, DQ. Não gosto de desanimar esses novatos, mas, sinceramente, eles vão e veem. Todos querem programar e todos querem ficar ricos e famosos =)

[]s


2008-10-20 Caloni:

Olá, Bruno.

Sua noção de que as idéias sempre "voltam à tona" faz muito sentido para mim. Essa é uma vantagem que não havia enxergado quando escrevi o artigo. Portanto, valeu por enriquecer um pouco o assunto =)

[]s


# Impressões do quinto encontro de CCPP

Caloni, 2008-10-07 <ccppbr> <blog> [up] [copy]

Pois é, passou, acabou... e foi muito bom!

E dessa vez me abstenho de fazer os comentários de sempre, visto que já está rolando uma discussão muito produtiva sobre o resultado desse último encontro, opiniões que, sinceramente, já refletem os pensamentos de todos que participaram desse magnânimo encontro de usuários.

// Comments

2008-10-08 A.F.:

Opa...

Logo terá um album de fotos do encontro, com dezenas de fotos...

E não sei como estará a qualidade, mas também uns vídeos de todas palestras.

[]s

A.F.


2008-10-14 Daniel Quadros:

Eu levei máquina, mas as pilhas estavam descarregadas :(

Estou contando com as fotos do "fotógrafo oficial".


2008-10-08 Fernando Roberto:

Como assim não tem foto?

:-)


2008-10-08 Caloni:

Então, eu sou daqueles das antigas, que só leva máquina pra viagem de passeio =)

Porém, provavelmente nosso amigo DQ irá publicar os flashes do dia. É só aguardar a "revelação".

[]s


# Como usar WTL com o ATL do DDK

Caloni, 2008-10-15 <computer> <archive> [up] [copy]

Eu simplemente não entendo a organização dos cabeçalhos e fontes dos SDKs da Microsoft. Houve uma vez em que o ATL era distribuído junto com o SDK, e dessa forma conseguíamos usar o WTL sem ônus. Porém, um belo dia, isso é retirado do pacote, para tristeza dos que já haviam convertido a biblioteca de janelas para fonte aberto.

No entanto, num belo dia, qual não foi minha surpresa ao notar umas pastinhas chamadas atl21, atl30 e atl71 dentro da distribuição do WDK (o finado DDK, renomeado sabe-se-lá-por-quê)? Pelo visto, tem alguém arrastando coisa errada pra onde não devia nos instaladores de Seattle. Esses estagiários!

O fato é que eles fizeram isso, e agora é possível ter o WTL mais novo compilado com o WDK. E nem é tão difícil assim.

A primeira coisa a fazer é obter o tal do WDK. Para variar um pouco, agora existe (existia) um processo de registro antes de obter acesso ao download, mais ou menos nos termos da Borland para baixar o C++ Builder ou Turbo Pascal ou o Developer Studio.

Aliás, para os que baixaram esses produtos gratuitos da Borland versão C++ e não funcionou em algumas máquinas, como foi o meu caso, está disponível para baixar uma versão mais nova; dessa vez não vi nenhum problema na compilação e depuração. Ainda.

Após instalado, em qualquer lugar da sua escolha, configure no seu Visual Studio o caminho de onde se encontra a pasta atl71 (ou a 30, ou a 21). Aproveite também para colocar a pasta do WTL e o diretório de LIBs:

Isso vai fazer com que pelo menos os exemplos que vêem com o WTL compilem.

No entanto, você verá o seguinte erro durante a compilação dos recursos:


------ Build started: Project: MTPad, Configuration: Debug Win32 ------
Compiling resources...
Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0
Copyright (C) Microsoft Corporation.  All rights reserved.
Linking...
CVTRES : fatal error CVT1100: duplicate resource.  type:MANIFEST, name:1, language:0x0409
LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
Build log was saved at "file://c:\Lng\WTL\Samples\MTPad\Debug\BuildLog.htm"
MTPad - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Para resolver esse problema, remova a inclusão do arquivo de manifesto no arquivo RC:

2 TEXTINCLUDE DISCARDABLE
BEGIN
    "#include ""atlres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE DISCARDABLE
BEGIN
    "CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST ""res\\\\MTPad.exe.manifest""\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED

...

#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "res\\MTPad.exe.manifest"

/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

Depois dessa alteração, deve ainda existir o seguinte erro de linquedição:

------ Build started: Project: MTPad, Configuration: Debug Win32 ------
Compiling resources...
Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0
Copyright (C) Microsoft Corporation.  All rights reserved.
Linking...
mtpad.obj : error LNK2019: unresolved external symbol
   "void * __stdcall ATL::__AllocStdCallThunk(void)" (bla bla bla)
mtpad.obj : error LNK2019: unresolved external symbol
   "void __stdcall ATL::__FreeStdCallThunk(void *)" (bla bla bla)
.\Debug/MTPad.exe : fatal error LNK1120: 2 unresolved externals
Build log was saved at "file://c:\Lng\WTL\Samples\MTPad\Debug\BuildLog.htm"
MTPad - 3 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Esse problema ocorre porque as funções de alocação e desalocação de memória da ATL estão em outra LIB que os exemplos da WTL desconhecem. Para resolver, basta incluir essa nova dependência:

#pragma comment(lib, "atlthunk.lib")

E pronto! Agora temos todo o poder das 500 milhões de classes da ATL aliadas à ilimitada flexibilidade das classes de janelas da WTL.

Para aprender a usar WTL

// Comments

2008-10-15 Daniel Quadros:

Falando no servidores em Seatle, você viu a foto em

http://blogs.msdn.com/e7/archive/2008/09/05/organizing-the-windows-7-project.aspx ? (2026-03-21 link quebrado)


2008-10-16 Caloni:

Amazing! 0_0

s


# A Alça Dentro do Fio Gerou um Bloqueio da Morte

Caloni, 2008-10-21 <essays> <blog> [up] [copy]

Estava folheando um livro fenomenal que meu amigo havia pedido emprestado para ler quando me deparei com algumas traduções no mínimo curiosas. O exemplar em questão era o primeiro Windows Internals, publicado após o lançamento da primeira versão do Windows NT, uma plataforma escrita (quase) inteiramente do zero para suplantar as versões 9x (Windows 95 e 98), que herdaram do DOS algumas partes indesejáveis em sistemas operacionais modernos.

Sabe-se lá por que essa edição foi traduzida. É interessante notar que naquela época foi dado um tratamento especial a alguns termos e conceitos já comuns no dia-a-dia do programador americano, apesar de quase nenhum desses termos ter se mantido em sua versão original. Os exemplos mais gritantes são as threads (fios ou linhas), os dead locks (bloqueios da morte) e os handles (alças). Apesar de não ter nada contra traduzir termos do inglês para português (e vice-versa) algumas coisas incomodam em tradução de livros técnicos.

Um bom exemplo são ponteiros. Ler em um dado capítulo "(...) é muito importante inicializar seus ponteiros antes de usá-los" para, depois de nos acostumarmos com o termo, ler em outro capítulo "(...) sabe-se que a pior desgraça para um programador C são os famigerados apontadores selvagens". Você resolveria esse tipo de problema definindo um vocabulário em comum com todo o livro (importantíssimo se ele está sendo traduzido por mais de uma pessoa) e ainda informaria o leitor qual o termo original, caso ele precise pesquisar sobre ele fora do livro. Com essa informação, que pode ser usada apenas nos primeiros usos da palavra ou em um glossário à parte, agradaria gregos e troianos: "os ponteiros em C (pointers) são um recurso rico e necessário para a escrita de programas de baixo/médio nível".

Um exemplo notável é o famoso livro de algoritmos em C da O'Reilly, que mesmo na nova edição com uma errata de 49 itens foi possível detectar mais erros. Um exemplo que me lembro era de uma função do algoritmo bitree. Nele havia uma variável com o nome orig que três linhas abaixo estava "traduzida" para original. É importante aqui diferenciar que no original não consta esse erro da troca do nome da variável.

Isso acaba sendo pior do que não colocar a versão em inglês, pois dá a impressão que não existe significado a ser explicado. Por exemplo, ver antes do capítulo sobre threads a passagem "... quando um fio espera o outro e vice-versa, acontece o terrível bug da trava da morte". Para quem não descobriu o que foi escrito no original, se trata de duas threads (fios) causando um deadlock (trava da morte), cujo termo inclusive é usado no seu original na Wikipédia em português.

Esses exemplos, salvo o exemplo do livro de algoritmos, foram criados para ilustrar os tipos de erros mais comuns em traduções de livros técnicos, e não estão relacionados com qualquer livro em específico. Então o que era inicialmente para ajudar as pessoas que estão iniciando alguns conceitos acaba por prejudicar ainda mais o aprendizado, gerando aquele tipo de confusão que só com ajuda extra (internet, professor, colega) pode ser resolvida.

Assim como no vocabulário comum corrente, em que existem palavras dificilmente adaptáveis ou traduzíveis em um termo comum, como shopping e show, no meio técnico brotam as mais variadas expressões "estrangeirísticas". Algumas são muito difíceis de encontrar seu primo lusófono, como link e login. Outros, no entanto, exageram um pouco as coisas, a ponto de conjugarmos um verbo em inglês usando nosso sistema gramatical: se você "stopar" o "debugador" vai "crashear" todo o sistema, porque esse software tá "bugado"! (1)

O fato é que não há escapatória para quem trabalha nessa área, e no fundo isso é uma coisa boa, pois é da leitura técnica em inglês que podemos estender o nosso conhecimento além das barreiras do ponto com ponto br e encontrar conteúdo extremamente interessante (e inédito em nossa língua) para aprender. Se não estivéssemos abarrotados de estrangeirismos talvez fosse um pouco mais difícil fazer o switch entre essas duas linguagens.

(1) Ironicamente 12 anos depois deste artigo ser escrito o verbo bugar virou uma gíria corrente entre jovens.

// Comments

2008-10-22 Daniel Quadros:

Na minha pequena experiência como autor e menor ainda como tradutor (somente 1 livro), eu diria que achar uma forma de colocar termos técnicos estrangeiros é uma coisa complicada e sem possibilidade de vitória... Me irrita muito o uso desnecessário do inglês quando existem termos equivalentes em português. "Aportuguesar" soa bem na hora de falar, mas fica estranho quando escrito (ressetar é com um s ou dois?). É também um processo contínuo, a cada ano uma expressão em português se consolida. Sobre os exemplos citados: "linha de execução" no lugar de thread até me soa poético, porém alça como tradução de handle me dá calafrios. Gabarito no lugar de template não é totalmente incorreto pois gabarito também pode ser usado para se referir a um modelo usado na produção/reprodução de alguma coisa.

Uma curiosidade: lá por volta de 1980 eu tive aula de eletrônica digital na Poli com o Prof Antonio Zuffo (o filho dele continua atuando na área e aparece na midia de vez em quando). Ele foi autor de um livro onde todas as siglas tradicionais (como RAM, ROM, CPU, etc) eram traduzidas. O nosso apelido para ele era Zovni!


2008-10-21 Sergio CBJ:

Infelizmente eu já li livros em que eles se davam o trabalho de traduzir até as siglas.

Mas esse "estrangeirismo" eu até gosto.. talvez eu esteja advogando em causa própria mas como você bem concluiu no final do post, eles ajudam muito a passar do portugues para o ingles gradativamente.

No entando, eu acho o portingles uma boa linguagem para blogs e artigos informais, mas para um livro que pretende manter a seriedade é outra história.

Bem, que atire a primeira pedra aquele que nunca falou "putz, essa droga bugo" ou "ta todo bugado" =P


2008-10-23 Sergio CBJ:

sabe, agora que me lembrei.. a um tempo atrás eu estava conversando com um amigo biólogo.. e ele estava me explicando a briga deles para dizer se um virus é ou não um ser vivo e como essa discussão não tem fim por ser uma discussão mais filosofal do que qualquer outra coisa.(eles discutem o que é a vida por si só para saber se um virus é ou não um ser vivo o0)

Na hora eu ri e pensei como é engraçado a forma como as ciencias que deveriam ser as mais exatas as vezes se baseiam em algo tão relativo quanto a opnião humana e pensei alto: "graças a deus que nos meus if's ou é TRUE ou é FALSE".

Mas aqui está uma discussão completamente voltada a opnião humana, já que traduzir ou não é questão de ponto de vista e ainda não desenvolveram nenhum standard para expressões que devem ou não ser traduzidas.Ou seja, a programação não é tão exata assim também. =/


2008-12-04 Victor Hugo:

Só um programador vindo do fefeléche pra fazer um artigo tão legal!

Parabéns, suas opniões são espelhos das minhas!


2008-10-21 ViniGodoy:

Aliás, algo que sempre me chamou atenção é que esses livros geralmente tem revisores técnicos! Sinceramente, erros tão grotescos podem passar se gente da área ajuda na tradução?

Também faltou citar o interessantístimo "gabarito" (template) na tradução do não menos clássico livro do Stroustrup. Mas tenho que admitir que o livro "Padrões de Projeto" foi muito bem traduzido. Um viva para o tradutor e para os revisores, que resolveram manter o nome dos padrões em inglês.


2008-10-21 Caloni:

Olá, Sergio.

De fato, no meu dia-a-dia proclamo e reclamo sobre tudo em inglês, gastando todos os termos possíveis e imagináveis. Nem parece uma afirmação de alguém que tenta zelar pelo excesso de estrangeirismos nos artigos deste humilde blogue =)

[]s


2008-10-23 Caloni:

É, meu caro, Sergio, quando a coisa cai no campo das línguas humanas, as coisas ficam menos lógicas; porém, mais ricas!

[]s


# Como funciona o PsExec

Caloni, 2008-10-29 <computer> <blog> [up] [copy]

Semana passada precisei reproduzir o comportamento da ferramenta PsExec em um projeto, o que me fez sentir alguma nostalgia dos tempos em que eu fazia engenharia reversa todo dia. Este breve relato (espero) reproduz os passos que segui para descobrir o que esse programa tão útil quanto perigoso faz.

Dados conhecidos

Sabe-se que o PsExec consegue executar um programa remotamente, ou seja, de uma máquina para outra, outra essa que chamaremos de máquina-alvo. O programa a ser executado geralmente deve estar disponível na própria máquina-alvo (condição ideal). Além da simples execução, para aplicativos console ele permite ainda a interação como se estivéssemos executando o programa remoto em nossa própria máquina local. Ele consegue isso redirecionando sua entrada e saída, o que o torna, como nos descreve o próprio autor, um "telnet light":

psexec \\maquina-alvo [-u admin-na-maquina-alvo] cmd.exe

Além desse comportamento já muito útil ainda existe um bônus que se trata de especificar um executável local que será copiado remotamente para a máquina-alvo e executado. Esse é o comportamento que espero imitar:

psexec \\maquina-alvo [-c c:\tests\myprogram.exe] [-u admin-na-maquina-alvo]
PsExec v1.72 - Execute processes remotely Copyright (C) 2001-2006 Mark Russinovich
Sysinternals - www.sysinternals.com
Microsoft Windows XP [versão 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

No teste acima o myprogram.exe é somente o cmd.exe renomeado. Um teste básico =)

Primeiro passo: reproduzir o comportamento analisado e coletar pistas

Já fizemos isso logo acima. Se trata apenas de observar o programa funcionando. Ao mesmo tempo em que entendemos seu modus operandi coletamos pistas sobre suas entranhas. No caso do PsExec, que faz coisas além-mar, como redirecionar os pipes de entrada/saída de um programa console, iremos checar a existência de algum serviço novo na máquina-alvo e arquivos novos que foram copiados, além de opcionalmente dar uma olhada no registro. Ferramentas da própria SysInternals como Process Explorer e Process Monitor também são úteis nessa análise inicial.

Como podemos ver, um serviço com o nome de PsExec foi criado na máquina-alvo. Se procurarmos saber o caminho do arquivo que corresponde a esse serviço, tanto pelo Process Explorer ou o Service Manager, descobriremos que se trata de um arquivo no diretório do windows chamado psexecsvc.exe.

Se o arquivo existe nessa pasta, então é óbvio que alguém o copiou. Resta saber como.

Segundo passo: acompanhar o processo lentamente

Nessa segunda fase, podemos refazer o comportamento esperado inúmeras vezes, coletando dados e pensando a partir dos dados obtidos. Para esse caso,  como quase todos que analiso, vou usar o nosso amigo [WinDbg]. Para isso, como tenho sempre minhas ferramentas disponíveis no ambiente onde trabalho, basta digitar "windbg" antes do comando anterior e dar uma olhada em algumas APIs-chave, como a criação/abertura de arquivos e a criação de serviços. Note que é importante fazer isso em um escopo limitado para não perdermos horas de análise. Descobrir coisas como, por exemplo, que as ações do PsExec só começam a ser executadas após a digitação da senha do usuário, pode ajudar, pois daí só começo minha análise a partir desse ponto.

windbg psexec \\maquina-alvo -u admin cmd.exe
PsExec v1.72 - Execute processes remotely
Copyright (C) 2001-2006 Mark Russinovich
Sysinternals - www.sysinternals.com

Password:

ntdll!DbgBreakPoint:
7c90120e cc              int     3
0:001> bp kernel32!CreateFileW
0:001> bp advapi32!CreateServiceW
0:001> g

Connecting to maquina-alvo...

Breakpoint 0 hit
eax=40150000 ebx=0011ee90 ecx=00000000 edx=00005078 esi=7c80932e edi=0011eeb0
eip=7c8107f0 esp=0011ee70 ebp=0011eed0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
kernel32!CreateFileW:
7c8107f0 8bff            mov     edi,edi
0:000> du poi(@esp+4)
0011ee90  "\\.\PIPE\wkssvc"
0:000> k 50 // pilha muito grande!
ChildEBP RetAddr
0011ee6c 77dc4b92 kernel32!CreateFileW
0011eed0 77dc4369 RPCRT4!NMP_Open+0x17a
0011ef1c 77dc48d3 RPCRT4!OSF_CCONNECTION::TransOpen+0x5e
0011ef70 77dc4a5d RPCRT4!OSF_CCONNECTION::OpenConnectionAndBind+0xbc
0011efb4 77dc49ac RPCRT4!OSF_CCALL::BindToServer+0x104
0011f018 77dbfdbc RPCRT4!OSF_BINDING_HANDLE::AllocateCCall+0x2b6
0011f048 77db8a01 RPCRT4!OSF_BINDING_HANDLE::NegotiateTransferSyntax+0x28
0011f060 77db8a38 RPCRT4!I_RpcGetBufferWithObject+0x5b
0011f070 77db906d RPCRT4!I_RpcGetBuffer+0xf
0011f080 77e3460b RPCRT4!NdrGetBuffer+0x28
0011f460 5bcb9d7c RPCRT4!NdrClientCall2+0x195
0011f474 5bcb9d1e NETAPI32!NetrWkstaGetInfo+0x1b
0011f4bc 71c78cc2 NETAPI32!NetWkstaGetInfo+0x38
0011f4e0 71c78a75 NETUI1!WKSTA_10::I_GetInfo+0x21
0011f4e8 71be1843 NETUI1!NEW_LM_OBJ::GetInfo+0x1c
0011fadc 71be31aa ntlanman!CheckLMService+0x3d
00120464 71be3058 ntlanman!AddConnection3Help+0x3e
0012118c 71be2e29 ntlanman!AddConnectionWorker+0x37c
001211b0 71ae461a ntlanman!NPAddConnection3+0x1f
001211d8 71ae45ac MPR!CUseConnection::TestProviderWorker+0x47
00121aa8 71ae2445 MPR!CUseConnection::TestProvider+0x62
00121b08 71ae431d MPR!CRoutedOperation::GetResult+0x10f
00121da4 71ae2348 MPR!CUseConnection::GetResult+0x180
00121ddc 71ae22fd MPR!CMprOperation::Perform+0x4d
00121de8 71ae4505 MPR!CRoutedOperation::Perform+0x22
00121e98 71ae50f0 MPR!WNetUseConnectionW+0x58
00121ec0 00401796 MPR!WNetAddConnection2W+0x1c
001225d0 0032002e image00400000+0x1796
001225d4 0030002e 0x32002e
001225d8 0034002e 0x30002e
001225dc 00000000 0x34002e

Uma rápida busca no Google nos informa que o pipe querendo ser aberto pertence à lista de pipes que estão sempre disponíveis nas máquinas para responder às requisições do sistema. São importantes para a comunicação entre processos (IPC, Inter Process Communication). No entanto, quem usa esse pipe é o sistema, e ele foi chamado, como pudemos ver, pela função WNetAddConnection2W.

Se analisarmos mais a fundo a pilha de chamadas conseguiremos dar um olhada nos parâmetros passados. Para isso existe a opção de mostrar os argumentos passados para as funções ao exibir a pilha:

0:000> kv 50
ChildEBP RetAddr  Args to Child
0011ee6c 77dc4b92 0011ee90 c0000000 00000003 kernel32!CreateFileW (FPO:
0011eed0 77dc4369 00147140 001463f8 005b4b46 RPCRT4!NMP_Open+0x17a (FPO:
...
00121e98 71ae50f0 00000000 00121ee4 004182a0 MPR!WNetUseConnectionW+0x58
00121ec0 00401796 00121ee4 004182a0 004139e0 MPR!WNetAddConnection2W+0x1c
001225d0 0032002e 0030002e 0034002e 00000030 image00400000+0x1796
001225d4 0030002e 0034002e 00000030 00000000 0x32002e
001225d8 0034002e 00000030 00000000 00000000 0x30002e
001225dc 00000000 00000000 00000000 00000000 0x34002e
0:000> db 00121ee4
00121ee4  00 00 00 00 00 00 00 00-00 00 00 00 03 00 00 00  ................
00121ef4  e2 1e 12 00 04 1f 12 00-00 00 00 00 00 00 00 00  ................
00121f04  5c 00 5c 00 31 00 30 00-2e 00 32 00 2e 00 30 00  \.\.1.0...2...0.
00121f14  2e 00 34 00 30 00 5c 00-49 00 50 00 43 00 24 00  ..4.0.\.I.P.C.$.
00121f24  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00121f34  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00121f44  cc da 90 7c c8 2d 91 7c-ec 07 00 00 88 1f 12 00  ...|.-.|........
00121f54  88 1f 12 00 00 00 00 00-f2 20 12 00 e0 24 12 00  ......... ...$..

Ele tenta abrir uma conexão com a máquina-alvo em seu compartilhamento de IPC, que como já vimos serve para comunicação entre processos, até entre máquinas distintas. Dessa forma, descobrimos um dos pontos importantes no funcionamento do PsExec: ele usa o nome e senha fornecidos para abrir uma comunicação remota no compartilhamento IPC$.

Depois sugem várias paradas ao CreateFile, de maneira que a melhor forma de acompanhar isso é colocando um "dumpezinho" de memória na sua parada:

0:000> bp kernel32!CreateFileW "du poi(@esp+4)"
breakpoint 0 redefined
0:000> g
0011ee90  "\\.\PIPE\wkssvc"
eax=40150000 ebx=0011ee90 ecx=00000000 edx=00005d6e esi=7c80932e edi=0011eeb0
eip=7c8107f0 esp=0011ee70 ebp=0011eed0 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
kernel32!CreateFileW:
7c8107f0 8bff            mov     edi,edi
0:000> g
0011f474  "\\.\PIPE\wkssvc"
eax=40160000 ebx=0011f474 ecx=00000000 edx=00005d77 esi=7c80932e edi=0011f494
eip=7c8107f0 esp=0011f454 ebp=0011f4b4 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
kernel32!CreateFileW:
7c8107f0 8bff            mov     edi,edi
0:000> g
0011f210  "\\.\PIPE\wkssvc"
eax=40160000 ebx=0011f210 ecx=00000000 edx=00005d7a esi=7c80932e edi=0011f230
eip=7c8107f0 esp=0011f1f0 ebp=0011f250 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
kernel32!CreateFileW:
7c8107f0 8bff            mov     edi,edi
0:000> g
0012213c  "\\10.2.0.40\ADMIN$\PSEXESVC.EXE"
eax=00122090 ebx=00000003 ecx=00000000 edx=009300d0 esi=00000080 edi=ffffffff
eip=7c8107f0 esp=00122064 ebp=001220ac iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
kernel32!CreateFileW:
7c8107f0 8bff            mov     edi,edi

Muito bem! Chegamos a mais um ponto importante de nossa análise: o psexecsvc.exe é copiado através do compartilhamento ADMIN$ remotamente (diretório c:\windows). Esse compartilhamento se torna acessível, uma vez que uma conexão autenticada já foi aberta. Se listarmos as conexões existentes, veremos o compartilhamento IPC$ aberto:

>net use
Novas conexões serão lembradas.

Status       Local     Remoto                    Rede

-------------------------------------------------------------------------------
OK                     \\10.2.0.40\IPC$          Rede Microsoft Windows
Comando concluído com êxito.

>

Também podemos notar que, enquanto estamos parados depurando o processo psexec.exe, temos acesso ao compartilhamento admin$:

A análise desses fatos demonstra como é importante fazer as coisas, pelo menos na fase "iniciante",  bem lentamente, e entender a mudança de estado durante o processo. Nem sempre isso é possível, é verdade, ainda mais quando estamos falando de análise de kernel. Mas, quando as condições permitem, vale a pena pensar antes de fazer.

Voltando à análise: temos direitos remotos nessa máquina. Dessa forma, fica fácil criar um serviço remotamente, que é o que faz o nosso amigo PsExec:

0:000> g
Breakpoint 1 hit
eax=00410870 ebx=00410870 ecx=00147a68 edx=00410844 esi=00410844 edi=00147a68
eip=77fb7381 esp=001224e4 ebp=001228dc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ADVAPI32!CreateServiceW:
77fb7381 6a20            push    20h

0:000> du poi(@esp+8)
00410870  "PSEXESVC"

0:000> du poi(@esp+8*4)
001228dc  "%SystemRoot%\PSEXESVC.EXE"

Pronto. Isso era tudo que precisava para conseguir reproduzir seu comportamento. Agora posso fazer isso programando ou até manualmente:

C:\Tests>net use \\10.2.0.40\ipc$ /user:admin
A senha ou o nome de usuário é inválido para \\10.2.0.40\ipc$.

Digite a senha para que 'admin' se conecte a '10.2.0.40':
Comando concluído com êxito.

C:\Tests>net use
Novas conexões serão lembradas.

Status       Local     Remoto                    Rede

-------------------------------------------------------------------------------
OK                     \\10.2.0.40\ipc$          Rede Microsoft Windows
Comando concluído com êxito.

C:\Tests>copy myprogram.exe \\10.2.0.40\admin$
1 arquivo(s) copiado(s).

C:\Tests>sc \\10.2.0.40 create MyProgram binPath= %systemroot%\myprogram.exe
[SC] CreateService SUCCESS

O resto do comportamento, como o redirecionamento de entrada e saída e execução do processo na conta especificada, embora muito interessante, não me interessa de imediato. Quem sabe interesse a você, e não tenhamos uma continuação dessa análise em um outro blogue de "desmontagem" por aí =)

// Comments

2009-01-27 Caloni:

Olá, Victor.

Não fui eu que desenvolvi esse programa. Recomendo que dê uma pesquisada na internet para ver se outras pessoas já tiveram o mesmo problema que você.

Só observo que o formato grupos\usuário não existe; tente domínio\usuário, ou máquina\usuário.

[]s


2009-01-26 victor:

Quando eu tento dar o comando Psexec dá acesso negado...

eu tento colocar o -u Administrador e não vai

eu tento colocar o -u Administradores\Administrador e não vai...

não sei mais o que fazer...

se puder mande a resposta pro meu email ;d


[2008-09] [2008-11]