Why can't bitcoin miners modify transaction outputs? I am learning the Bitcoin protocol by reading the bitcoin developer reference documentation.

As far as I know, a raw transaction consists of:


Version (which is always 1)
Inputs. Each input contains:


Hash of the transaction that contains the output that we are going to spend here
Index of the output in that transaction
Script that satisfies the conditions placed in the script of the referenced ouput.

Outputs. Each output contains:


8 bytes for the value in satoshis
Script with the conditions that must be satisfied in order for this output to be spent.

Locktime (which is usually 0)


I am not very sure what the script of the inputs contain, but I guess it should contain the public key, and a signed message.

My question is, why can't the miner modify the scripts in the outputs (replacing the address by their own), if those scripts are not part of the message that the real user had to sign?

Or maybe this question would be better asked like this: What is signed in the input scripts?
What is signed in the input scripts?


Depends. 

The case of a P2PKH spending transaction, the scriptSig (input script) for each input will contain a ECDSA signature and a byte which donates what exactly was signed called the SIGHASH flag. In almost all cases this is SIGHASH_ALL, which means that the signature covers the entirety of the transaction outputs and inputs, less other signatures. If the transaction output script is modified and any input has signed it with SIGHASH_ALL, that signature would be invalidated and the transaction can not be included in a block. 

Other flags can have the effect you describe, if I make a transaction which only signs a single input with SIGHASH_NONE (this signature only covers the input), then anybody in the network is free to modify the outputs as much as they want before it gets buried in a block. Nobody uses it like that for exactly this reason.

There's two other flags available today SIGHASH_SINGLE and SIGHASH_ANYONECANPAY. The former allows you to sign only one of the outputs and ignores the rest (eg vin:1 signs only vout:1), however this is buggy and not at all intuitive. The latter allows you to make transactions where the inputs are a wildcard, spend this output to this script, and make up the deficit using whatever other inputs you want. 

In general nobody uses SIGHASH flags, the majority of all transactions are strictly SIGHASH_ALL. 


  I am not very sure what the script of the inputs contain, but I guess it should contain the public key, and a signed message.


This depends entirely on what type of output is being spent, but we'll assume it's a very typical Pay to Pubkey Hash (address) transaction. In this case the scriptSig is extremely simple. 

304402204bc6ed9b0122fc145031d4d9f6a30fbb28b63d152e3848c785a65f1e0b97ea8d02205a99bc13ba9293526ed175947cb756c5e3fca0a98890b88551e3e6c4c0bb6f5601
04988b34239b2f1c2441db4d50911b0550350414ce00b88f8dd39964f1a8631824db8e78b61d0ea6f3d9fcffcf2cd20be7d88a1583854682db4d136acd08542c3d


We have two data items, the first is an ECDSA signature in DER format, and the public points of the P2PKH output we are spending. The last byte of the signature is the SIGHASH flag, which in this case is 0x01 or SIGHASH_ALL. 

If you want to follow along with how these structures work, webbtc.com has a great script visualization tool which will allow you to see how these go together. In particular here is a reasonable example transaction with one input and output, and here is a play through the script execution which does a good job of explaining how and why it is valid.